Refactor DepthStencilState. TODO: add validation tests

- defaults to depth and stencil tests off
- whether or not depth and stencil tests are enabled is inferred from the comparison functions and stencil operations
- only one stencil reference. D3D12 does not support separate references
- change SetDepthWriteMode to SetDepthWriteEnabled and use a bool instead of enum
- Create PersistentPipelineState class for OpenGL backend with simple state tracking
- Add validation so DepthStencilState properties are only set once
- Update API usage in HelloDepthStencil
- refactor tracking of the DepthStencilState in the Metal backend
- validate that compute pipeline does not have a depth stencil state
This commit is contained in:
Austin Eng 2017-06-01 11:30:03 -04:00 committed by Corentin Wallez
parent f51be34864
commit 1063439d5d
20 changed files with 451 additions and 257 deletions

View File

@ -176,7 +176,6 @@ void init() {
.SetAttribute(0, 0, nxt::VertexFormat::FloatR32G32B32, 0) .SetAttribute(0, 0, nxt::VertexFormat::FloatR32G32B32, 0)
.SetAttribute(1, 0, nxt::VertexFormat::FloatR32G32B32, 3 * sizeof(float)) .SetAttribute(1, 0, nxt::VertexFormat::FloatR32G32B32, 3 * sizeof(float))
.SetInput(0, 6 * sizeof(float), nxt::InputStepMode::Vertex) .SetInput(0, 6 * sizeof(float), nxt::InputStepMode::Vertex)
.SetInput(1, 6 * sizeof(float), nxt::InputStepMode::Vertex)
.GetResult(); .GetResult();
nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder() nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder()
@ -243,8 +242,8 @@ void init() {
CreateDefaultRenderPass(device, &renderpass, &framebuffer); CreateDefaultRenderPass(device, &renderpass, &framebuffer);
auto depthStencilState = device.CreateDepthStencilStateBuilder() auto depthStencilState = device.CreateDepthStencilStateBuilder()
.SetDepthEnabled(true) .SetDepthCompareFunction(nxt::CompareFunction::Less)
.SetStencilEnabled(false) .SetDepthWriteEnabled(true)
.GetResult(); .GetResult();
pipeline = device.CreatePipelineBuilder() pipeline = device.CreatePipelineBuilder()
@ -257,12 +256,9 @@ void init() {
.GetResult(); .GetResult();
auto planeStencilState = device.CreateDepthStencilStateBuilder() auto planeStencilState = device.CreateDepthStencilStateBuilder()
.SetDepthEnabled(true) .SetDepthCompareFunction(nxt::CompareFunction::Less)
.SetDepthWrite(nxt::DepthWriteMode::Disabled) .SetDepthWriteEnabled(false)
.SetStencilEnabled(true) .SetStencilFunction(nxt::Face::Both, nxt::CompareFunction::Always, nxt::StencilOperation::Keep, nxt::StencilOperation::Keep, nxt::StencilOperation::Replace)
.SetStencilCompareFunction(nxt::Face::Both, nxt::CompareFunction::Always)
.SetStencilOperation(nxt::Face::Both, nxt::StencilOperation::Keep, nxt::StencilOperation::Keep, nxt::StencilOperation::Replace)
.SetStencilMask(nxt::Face::Both, 0xff, 0xff)
.GetResult(); .GetResult();
planePipeline = device.CreatePipelineBuilder() planePipeline = device.CreatePipelineBuilder()
@ -275,12 +271,9 @@ void init() {
.GetResult(); .GetResult();
auto reflectionStencilState = device.CreateDepthStencilStateBuilder() auto reflectionStencilState = device.CreateDepthStencilStateBuilder()
.SetDepthEnabled(true) .SetDepthCompareFunction(nxt::CompareFunction::Less)
.SetDepthWrite(nxt::DepthWriteMode::Enabled) .SetDepthWriteEnabled(true)
.SetStencilEnabled(true) .SetStencilFunction(nxt::Face::Both, nxt::CompareFunction::Equal, nxt::StencilOperation::Keep, nxt::StencilOperation::Keep, nxt::StencilOperation::Replace)
.SetStencilCompareFunction(nxt::Face::Both, nxt::CompareFunction::Equal)
.SetStencilOperation(nxt::Face::Both, nxt::StencilOperation::Keep, nxt::StencilOperation::Keep, nxt::StencilOperation::Replace)
.SetStencilMask(nxt::Face::Both, 0xff, 0x00)
.GetResult(); .GetResult();
reflectionPipeline = device.CreatePipelineBuilder() reflectionPipeline = device.CreatePipelineBuilder()
@ -320,13 +313,12 @@ void frame() {
.SetIndexBuffer(indexBuffer, 0, nxt::IndexFormat::Uint32) .SetIndexBuffer(indexBuffer, 0, nxt::IndexFormat::Uint32)
.DrawElements(36, 1, 0, 0) .DrawElements(36, 1, 0, 0)
.SetStencilReference(0x1)
.SetPipeline(planePipeline) .SetPipeline(planePipeline)
.SetStencilReference(0x1, 0x1)
.SetVertexBuffers(0, 1, &planeBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &planeBuffer, vertexBufferOffsets)
.DrawElements(6, 1, 0, 0) .DrawElements(6, 1, 0, 0)
.SetPipeline(reflectionPipeline) .SetPipeline(reflectionPipeline)
.SetStencilReference(0x1, 0x1)
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
.SetBindGroup(0, bindGroup[1]) .SetBindGroup(0, bindGroup[1])
.DrawElements(36, 1, 0, 0) .DrawElements(36, 1, 0, 0)

View File

@ -14,6 +14,9 @@
"See the License for the specific language governing permissions and", "See the License for the specific language governing permissions and",
"limitations under the License." "limitations under the License."
], ],
"bool": {
"category": "native"
},
"bind group": { "bind group": {
"category": "object" "category": "object"
}, },
@ -282,8 +285,7 @@
{ {
"name": "set stencil reference", "name": "set stencil reference",
"args": [ "args": [
{"name": "back reference", "type": "uint32_t"}, {"name": "reference", "type": "uint32_t"}
{"name": "front reference", "type": "uint32_t"}
] ]
}, },
{ {
@ -448,12 +450,6 @@
"name": "get result", "name": "get result",
"returns": "depth stencil state" "returns": "depth stencil state"
}, },
{
"name": "set depth enabled",
"args": [
{"name": "depth enabled", "type": "bool"}
]
},
{ {
"name": "set depth compare function", "name": "set depth compare function",
"args": [ "args": [
@ -461,56 +457,37 @@
] ]
}, },
{ {
"name": "set depth write", "name": "set depth write enabled",
"args" : [ "args" : [
{"name": "depth write mode", "type": "depth write mode"} {"name": "enabled", "type": "bool"}
] ]
}, },
{ {
"name": "set stencil enabled", "name": "set stencil function",
"args": [
{"name": "stencil enabled", "type": "bool"}
]
},
{
"name": "set stencil operation",
"args": [ "args": [
{"name": "face", "type": "face"}, {"name": "face", "type": "face"},
{"name": "stencil compare function", "type": "compare function"},
{"name": "stencil failure operation", "type": "stencil operation"}, {"name": "stencil failure operation", "type": "stencil operation"},
{"name": "depth failure operation", "type": "stencil operation"}, {"name": "depth failure operation", "type": "stencil operation"},
{"name": "stencil pass operation", "type": "stencil operation"} {"name": "stencil pass operation", "type": "stencil operation"}
] ]
}, },
{
"name": "set stencil compare function",
"args": [
{"name": "face", "type": "face"},
{"name": "stencil compare function", "type": "compare function"}
]
},
{ {
"name": "set stencil mask", "name": "set stencil mask",
"args": [ "args": [
{"name": "face", "type": "face"}, {"name": "face", "type": "face"},
{"name": "read mask", "type": "uint32_t"}, {"name": "mask", "type": "uint32_t"}
{"name": "write mask", "type": "uint32_t"}
] ]
} }
] ]
}, },
"depth write mode": {
"category": "enum",
"values": [
{"value": 0, "name": "disabled"},
{"value": 1, "name": "enabled"}
]
},
"device error callback": { "device error callback": {
"category": "natively defined" "category": "natively defined"
}, },
"face": { "face": {
"category": "bitmask", "category": "bitmask",
"values": [ "values": [
{"value": 0, "name": "none"},
{"value": 1, "name": "back"}, {"value": 1, "name": "back"},
{"value": 2, "name": "front"}, {"value": 2, "name": "front"},
{"value": 3, "name": "both"} {"value": 3, "name": "both"}
@ -638,7 +615,7 @@
{ {
"name": "set depth stencil state", "name": "set depth stencil state",
"args": [ "args": [
{"name": "input", "type": "depth stencil state"} {"name": "depth stencil state", "type": "depth stencil state"}
] ]
} }
] ]
@ -912,8 +889,5 @@
}, },
"uint32_t": { "uint32_t": {
"category": "native" "category": "native"
},
"bool": {
"category": "native"
} }
} }

View File

@ -85,6 +85,8 @@ list(APPEND BACKEND_SOURCES
${OPENGL_DIR}/CommandBufferGL.h ${OPENGL_DIR}/CommandBufferGL.h
${OPENGL_DIR}/OpenGLBackend.cpp ${OPENGL_DIR}/OpenGLBackend.cpp
${OPENGL_DIR}/OpenGLBackend.h ${OPENGL_DIR}/OpenGLBackend.h
${OPENGL_DIR}/PersistentPipelineStateGL.cpp
${OPENGL_DIR}/PersistentPipelineStateGL.h
${OPENGL_DIR}/PipelineGL.cpp ${OPENGL_DIR}/PipelineGL.cpp
${OPENGL_DIR}/PipelineGL.h ${OPENGL_DIR}/PipelineGL.h
${OPENGL_DIR}/PipelineLayoutGL.cpp ${OPENGL_DIR}/PipelineLayoutGL.cpp

View File

@ -573,6 +573,14 @@ namespace backend {
case Command::SetStencilReference: case Command::SetStencilReference:
{ {
SetStencilReferenceCmd* cmd = iterator.NextCommand<SetStencilReferenceCmd>(); SetStencilReferenceCmd* cmd = iterator.NextCommand<SetStencilReferenceCmd>();
if (lastPipeline->IsCompute()) {
HandleError("Can't set stencil reference in a compute pipeline");
return false;
}
if (currentRenderPass == nullptr) {
HandleError("Can't set stencil reference without an active render pass");
return false;
}
} }
break; break;
@ -766,11 +774,10 @@ namespace backend {
memcpy(values, data, count * sizeof(uint32_t)); memcpy(values, data, count * sizeof(uint32_t));
} }
void CommandBufferBuilder::SetStencilReference(uint32_t backReference, uint32_t frontReference) { void CommandBufferBuilder::SetStencilReference(uint32_t reference) {
SetStencilReferenceCmd* cmd = allocator.Allocate<SetStencilReferenceCmd>(Command::SetStencilReference); SetStencilReferenceCmd* cmd = allocator.Allocate<SetStencilReferenceCmd>(Command::SetStencilReference);
new(cmd) SetStencilReferenceCmd; new(cmd) SetStencilReferenceCmd;
cmd->backReference = backReference; cmd->reference = reference;
cmd->frontReference = frontReference;
} }
void CommandBufferBuilder::SetBindGroup(uint32_t groupIndex, BindGroupBase* group) { void CommandBufferBuilder::SetBindGroup(uint32_t groupIndex, BindGroupBase* group) {

View File

@ -68,7 +68,7 @@ namespace backend {
void EndRenderPass(); void EndRenderPass();
void SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data); void SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data);
void SetPipeline(PipelineBase* pipeline); void SetPipeline(PipelineBase* pipeline);
void SetStencilReference(uint32_t backReference, uint32_t frontReference); void SetStencilReference(uint32_t reference);
void SetBindGroup(uint32_t groupIndex, BindGroupBase* group); void SetBindGroup(uint32_t groupIndex, BindGroupBase* group);
void SetIndexBuffer(BufferBase* buffer, uint32_t offset, nxt::IndexFormat format); void SetIndexBuffer(BufferBase* buffer, uint32_t offset, nxt::IndexFormat format);

View File

@ -96,8 +96,7 @@ namespace backend {
}; };
struct SetStencilReferenceCmd { struct SetStencilReferenceCmd {
uint32_t backReference; uint32_t reference;
uint32_t frontReference;
}; };
struct SetBindGroupCmd { struct SetBindGroupCmd {

View File

@ -21,34 +21,43 @@ namespace backend {
// DepthStencilStateBase // DepthStencilStateBase
DepthStencilStateBase::DepthStencilStateBase(DepthStencilStateBuilder* builder) DepthStencilStateBase::DepthStencilStateBase(DepthStencilStateBuilder* builder)
: depthEnabled(builder->depthEnabled), stencilEnabled(builder->stencilEnabled), : depthInfo(builder->depthInfo), stencilInfo(builder->stencilInfo) {
depthInfo(builder->depthInfo), backStencilInfo(builder->backStencilInfo),
frontStencilInfo(builder->frontStencilInfo) {
} }
bool DepthStencilStateBase::DepthIsEnabled() const { bool DepthStencilStateBase::DepthTestEnabled() const {
return depthEnabled; return depthInfo.compareFunction != nxt::CompareFunction::Always;
} }
bool DepthStencilStateBase::StencilIsEnabled() const { bool DepthStencilStateBase::StencilTestEnabled() const {
return stencilEnabled; return (stencilInfo.back.compareFunction != nxt::CompareFunction::Always ||
stencilInfo.back.stencilFail != nxt::StencilOperation::Keep ||
stencilInfo.back.depthFail != nxt::StencilOperation::Keep ||
stencilInfo.back.depthStencilPass != nxt::StencilOperation::Keep ||
stencilInfo.front.compareFunction != nxt::CompareFunction::Always ||
stencilInfo.front.stencilFail != nxt::StencilOperation::Keep ||
stencilInfo.front.depthFail != nxt::StencilOperation::Keep ||
stencilInfo.front.depthStencilPass != nxt::StencilOperation::Keep);
} }
const DepthStencilStateBase::DepthInfo& DepthStencilStateBase::GetDepth() const { const DepthStencilStateBase::DepthInfo& DepthStencilStateBase::GetDepth() const {
return depthInfo; return depthInfo;
} }
const DepthStencilStateBase::StencilInfo& DepthStencilStateBase::GetBackStencil() const { const DepthStencilStateBase::StencilInfo& DepthStencilStateBase::GetStencil() const {
return backStencilInfo; return stencilInfo;
} }
const DepthStencilStateBase::StencilInfo& DepthStencilStateBase::GetFrontStencil() const {
return frontStencilInfo;
}
// DepthStencilStateBuilder // DepthStencilStateBuilder
enum DepthStencilStateSetProperties {
DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION = 0x1,
DEPTH_STENCIL_STATE_PROPERTY_DEPTH_WRITE_ENABLED = 0x2,
DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_FUNCTION = 0x4,
DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_MASK = 0x8,
DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_FUNCTION = 0x10,
DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_MASK = 0x20,
};
DepthStencilStateBuilder::DepthStencilStateBuilder(DeviceBase* device) : Builder(device) { DepthStencilStateBuilder::DepthStencilStateBuilder(DeviceBase* device) : Builder(device) {
} }
@ -56,53 +65,88 @@ namespace backend {
return device->CreateDepthStencilState(this); return device->CreateDepthStencilState(this);
} }
void DepthStencilStateBuilder::SetDepthEnabled(bool depthEnabled) {
this->depthEnabled = depthEnabled;
}
void DepthStencilStateBuilder::SetDepthCompareFunction(nxt::CompareFunction depthCompareFunction) { void DepthStencilStateBuilder::SetDepthCompareFunction(nxt::CompareFunction depthCompareFunction) {
if ((propertiesSet & DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION) != 0) {
HandleError("Depth compare property set multiple times");
return;
}
propertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION;
depthInfo.compareFunction = depthCompareFunction; depthInfo.compareFunction = depthCompareFunction;
} }
void DepthStencilStateBuilder::SetDepthWrite(nxt::DepthWriteMode depthWriteMode) { void DepthStencilStateBuilder::SetDepthWriteEnabled(bool enabled) {
depthInfo.depthWriteMode = depthWriteMode; if ((propertiesSet & DEPTH_STENCIL_STATE_PROPERTY_DEPTH_WRITE_ENABLED) != 0) {
HandleError("Depth write enabled property set multiple times");
return;
}
propertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_DEPTH_WRITE_ENABLED;
depthInfo.depthWriteEnabled = enabled;
} }
void DepthStencilStateBuilder::SetStencilEnabled(bool stencilEnabled) { void DepthStencilStateBuilder::SetStencilFunction(nxt::Face face, nxt::CompareFunction stencilCompareFunction,
this->stencilEnabled = stencilEnabled; nxt::StencilOperation stencilFail, nxt::StencilOperation depthFail, nxt::StencilOperation depthStencilPass) {\
} if (face == nxt::Face::None) {
HandleError("Can't set stencil function of None face");
return;
}
void DepthStencilStateBuilder::SetStencilOperation(nxt::Face face, nxt::StencilOperation stencilFail,
nxt::StencilOperation depthFail, nxt::StencilOperation stencilPass) {
if (face & nxt::Face::Back) { if (face & nxt::Face::Back) {
backStencilInfo.stencilFail = stencilFail; if ((propertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_FUNCTION) != 0) {
backStencilInfo.depthFail = stencilFail; HandleError("Stencil back function property set multiple times");
backStencilInfo.stencilPass = stencilPass; return;
}
propertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_FUNCTION;
stencilInfo.back.compareFunction = stencilCompareFunction;
stencilInfo.back.stencilFail = stencilFail;
stencilInfo.back.depthFail = depthFail;
stencilInfo.back.depthStencilPass = depthStencilPass;
} }
if (face & nxt::Face::Front) { if (face & nxt::Face::Front) {
frontStencilInfo.stencilFail = stencilFail; if ((propertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_FUNCTION) != 0) {
frontStencilInfo.depthFail = stencilFail; HandleError("Stencil front function property set multiple times");
frontStencilInfo.stencilPass = stencilPass; return;
}
propertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_FUNCTION;
stencilInfo.front.compareFunction = stencilCompareFunction;
stencilInfo.front.stencilFail = stencilFail;
stencilInfo.front.depthFail = depthFail;
stencilInfo.front.depthStencilPass = depthStencilPass;
} }
} }
void DepthStencilStateBuilder::SetStencilCompareFunction(nxt::Face face, nxt::CompareFunction stencilCompareFunction) { void DepthStencilStateBuilder::SetStencilMask(nxt::Face face, uint32_t mask) {
if (face & nxt::Face::Back) { if (face == nxt::Face::None) {
backStencilInfo.compareFunction = stencilCompareFunction; HandleError("Can't set stencil mask of None face");
return;
} }
if (face & nxt::Face::Front) {
frontStencilInfo.compareFunction = stencilCompareFunction;
}
}
void DepthStencilStateBuilder::SetStencilMask(nxt::Face face, uint32_t readMask, uint32_t writeMask) {
if (face & nxt::Face::Back) { if (face & nxt::Face::Back) {
backStencilInfo.readMask = readMask; if ((propertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_MASK) != 0) {
backStencilInfo.writeMask = writeMask; HandleError("Stencil back mask property set multiple times");
return;
}
propertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_BACK_MASK;
stencilInfo.back.mask = mask;
} }
if (face & nxt::Face::Front) { if (face & nxt::Face::Front) {
frontStencilInfo.readMask = readMask; if ((propertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_MASK) != 0) {
frontStencilInfo.writeMask = writeMask; HandleError("Stencil front mask property set multiple times");
return;
}
propertiesSet |= DEPTH_STENCIL_STATE_PROPERTY_STENCIL_FRONT_MASK;
stencilInfo.front.mask = mask;
} }
} }

View File

@ -29,31 +29,32 @@ namespace backend {
DepthStencilStateBase(DepthStencilStateBuilder* builder); DepthStencilStateBase(DepthStencilStateBuilder* builder);
struct DepthInfo { struct DepthInfo {
nxt::CompareFunction compareFunction = nxt::CompareFunction::Less; nxt::CompareFunction compareFunction = nxt::CompareFunction::Always;
nxt::DepthWriteMode depthWriteMode = nxt::DepthWriteMode::Enabled; bool depthWriteEnabled = false;
}; };
struct StencilInfo { struct StencilFaceInfo {
nxt::CompareFunction compareFunction = nxt::CompareFunction::Always; nxt::CompareFunction compareFunction = nxt::CompareFunction::Always;
nxt::StencilOperation stencilFail = nxt::StencilOperation::Keep; nxt::StencilOperation stencilFail = nxt::StencilOperation::Keep;
nxt::StencilOperation depthFail = nxt::StencilOperation::Keep; nxt::StencilOperation depthFail = nxt::StencilOperation::Keep;
nxt::StencilOperation stencilPass = nxt::StencilOperation::Keep; nxt::StencilOperation depthStencilPass = nxt::StencilOperation::Keep;
uint32_t readMask = 0xff; uint32_t mask = 0xff;
uint32_t writeMask = 0xff;
}; };
bool DepthIsEnabled() const; struct StencilInfo {
bool StencilIsEnabled() const; bool stencilTestEnabled;
StencilFaceInfo back;
StencilFaceInfo front;
};
bool DepthTestEnabled() const;
bool StencilTestEnabled() const;
const DepthInfo& GetDepth() const; const DepthInfo& GetDepth() const;
const StencilInfo& GetBackStencil() const; const StencilInfo& GetStencil() const;
const StencilInfo& GetFrontStencil() const;
private: private:
bool depthEnabled = false;
bool stencilEnabled = false;
DepthInfo depthInfo; DepthInfo depthInfo;
StencilInfo backStencilInfo; StencilInfo stencilInfo;
StencilInfo frontStencilInfo;
}; };
class DepthStencilStateBuilder : public Builder<DepthStencilStateBase> { class DepthStencilStateBuilder : public Builder<DepthStencilStateBase> {
@ -61,25 +62,21 @@ namespace backend {
DepthStencilStateBuilder(DeviceBase* device); DepthStencilStateBuilder(DeviceBase* device);
// NXT API // NXT API
void SetDepthEnabled(bool depthEnabled);
void SetDepthCompareFunction(nxt::CompareFunction depthCompareFunction); void SetDepthCompareFunction(nxt::CompareFunction depthCompareFunction);
void SetDepthWrite(nxt::DepthWriteMode depthWriteMode); void SetDepthWriteEnabled(bool enabled);
void SetStencilEnabled(bool stencilEnabled); void SetStencilFunction(nxt::Face face, nxt::CompareFunction stencilCompareFunction,
void SetStencilOperation(nxt::Face face, nxt::StencilOperation stencilFail, nxt::StencilOperation stencilFail, nxt::StencilOperation depthFail, nxt::StencilOperation depthStencilPass);
nxt::StencilOperation depthFail, nxt::StencilOperation stencilPass); void SetStencilMask(nxt::Face face, uint32_t mask);
void SetStencilCompareFunction(nxt::Face face, nxt::CompareFunction stencilCompareFunction);
void SetStencilMask(nxt::Face face, uint32_t readMask, uint32_t writeMask);
private: private:
friend class DepthStencilStateBase; friend class DepthStencilStateBase;
DepthStencilStateBase* GetResultImpl() override; DepthStencilStateBase* GetResultImpl() override;
bool depthEnabled; int propertiesSet = 0;
bool stencilEnabled;
DepthStencilStateBase::DepthInfo depthInfo; DepthStencilStateBase::DepthInfo depthInfo;
DepthStencilStateBase::StencilInfo backStencilInfo; DepthStencilStateBase::StencilInfo stencilInfo;
DepthStencilStateBase::StencilInfo frontStencilInfo;
}; };
} }

View File

@ -36,6 +36,11 @@ namespace backend {
return; return;
} }
if (IsCompute() && depthStencilState) {
builder->HandleError("Compute pipeline cannot have depth stencil state");
return;
}
if (!IsCompute() && !renderPass) { if (!IsCompute() && !renderPass) {
builder->HandleError("Pipeline render pass not set"); builder->HandleError("Pipeline render pass not set");
return; return;
@ -123,13 +128,17 @@ namespace backend {
if (!inputState) { if (!inputState) {
inputState = device->CreateInputStateBuilder()->GetResult(); inputState = device->CreateInputStateBuilder()->GetResult();
} }
if (!depthStencilState) { if (!depthStencilState && !IsCompute()) {
depthStencilState = device->CreateDepthStencilStateBuilder()->GetResult(); depthStencilState = device->CreateDepthStencilStateBuilder()->GetResult();
} }
return device->CreatePipeline(this); return device->CreatePipeline(this);
} }
bool PipelineBuilder::IsCompute() const {
return stageMask == nxt::ShaderStageBit::Compute;
}
void PipelineBuilder::SetLayout(PipelineLayoutBase* layout) { void PipelineBuilder::SetLayout(PipelineLayoutBase* layout) {
this->layout = layout; this->layout = layout;
} }

View File

@ -86,6 +86,8 @@ namespace backend {
PipelineBase* GetResultImpl() override; PipelineBase* GetResultImpl() override;
bool IsCompute() const;
Ref<PipelineLayoutBase> layout; Ref<PipelineLayoutBase> layout;
Ref<RenderPassBase> renderPass; Ref<RenderPassBase> renderPass;
uint32_t subpass; uint32_t subpass;

View File

@ -189,11 +189,12 @@ namespace metal {
DepthStencilState(Device* device, DepthStencilStateBuilder* builder); DepthStencilState(Device* device, DepthStencilStateBuilder* builder);
~DepthStencilState(); ~DepthStencilState();
MTLDepthStencilDescriptor* GetMTLDepthStencilDescriptor(); id<MTLDepthStencilState> GetMTLDepthStencilState();
private: private:
Device* device; Device* device;
MTLDepthStencilDescriptor* mtlDepthStencilDescriptor = nil;
id<MTLDepthStencilState> mtlDepthStencilState = nil;
}; };
class InputState : public InputStateBase { class InputState : public InputStateBase {
@ -230,8 +231,6 @@ namespace metal {
Device* device; Device* device;
id<MTLRenderPipelineState> mtlRenderPipelineState = nil; id<MTLRenderPipelineState> mtlRenderPipelineState = nil;
id<MTLDepthStencilState> mtlDepthStencilState = nil;
id<MTLComputePipelineState> mtlComputePipelineState = nil; id<MTLComputePipelineState> mtlComputePipelineState = nil;
MTLSize localWorkgroupSize; MTLSize localWorkgroupSize;
}; };

View File

@ -456,6 +456,8 @@ namespace metal {
lastPipeline->Encode(encoders.compute); lastPipeline->Encode(encoders.compute);
} else { } else {
ASSERT(encoders.render); ASSERT(encoders.render);
DepthStencilState* depthStencilState = ToBackend(lastPipeline->GetDepthStencilState());
[encoders.render setDepthStencilState:depthStencilState->GetMTLDepthStencilState()];
lastPipeline->Encode(encoders.render); lastPipeline->Encode(encoders.render);
} }
} }
@ -478,9 +480,7 @@ namespace metal {
ASSERT(encoders.render); ASSERT(encoders.render);
[encoders.render [encoders.render setStencilReferenceValue:cmd->reference];
setStencilFrontReferenceValue:cmd->frontReference
backReferenceValue:cmd->backReference];
} }
break; break;
@ -665,7 +665,7 @@ namespace metal {
// DepthStencilState // DepthStencilState
static MTLCompareFunction DepthStencilCompareFunction(nxt::CompareFunction compareFunction) { static MTLCompareFunction MetalDepthStencilCompareFunction(nxt::CompareFunction compareFunction) {
switch (compareFunction) { switch (compareFunction) {
case nxt::CompareFunction::Never: case nxt::CompareFunction::Never:
return MTLCompareFunctionNever; return MTLCompareFunctionNever;
@ -683,12 +683,10 @@ namespace metal {
return MTLCompareFunctionEqual; return MTLCompareFunctionEqual;
case nxt::CompareFunction::Always: case nxt::CompareFunction::Always:
return MTLCompareFunctionAlways; return MTLCompareFunctionAlways;
default:
ASSERT(false);
} }
} }
static MTLStencilOperation StencilOperation(nxt::StencilOperation stencilOperation) { static MTLStencilOperation MetalStencilOperation(nxt::StencilOperation stencilOperation) {
switch (stencilOperation) { switch (stencilOperation) {
case nxt::StencilOperation::Keep: case nxt::StencilOperation::Keep:
return MTLStencilOperationKeep; return MTLStencilOperationKeep;
@ -706,51 +704,38 @@ namespace metal {
return MTLStencilOperationIncrementWrap; return MTLStencilOperationIncrementWrap;
case nxt::StencilOperation::DecrementWrap: case nxt::StencilOperation::DecrementWrap:
return MTLStencilOperationDecrementWrap; return MTLStencilOperationDecrementWrap;
default:
ASSERT(false);
} }
} }
DepthStencilState::DepthStencilState(Device* device, DepthStencilStateBuilder* builder) DepthStencilState::DepthStencilState(Device* device, DepthStencilStateBuilder* builder)
: DepthStencilStateBase(builder), device(device) { : DepthStencilStateBase(builder), device(device) {
mtlDepthStencilDescriptor = [MTLDepthStencilDescriptor new]; MTLDepthStencilDescriptor* mtlDepthStencilDescriptor = [MTLDepthStencilDescriptor new];
if (DepthIsEnabled()) { if (DepthTestEnabled()) {
auto& depth = GetDepth(); auto& depth = GetDepth();
mtlDepthStencilDescriptor.depthCompareFunction = DepthStencilCompareFunction(depth.compareFunction); mtlDepthStencilDescriptor.depthCompareFunction = MetalDepthStencilCompareFunction(depth.compareFunction);
switch (depth.depthWriteMode) { mtlDepthStencilDescriptor.depthWriteEnabled = depth.depthWriteEnabled;
case nxt::DepthWriteMode::Disabled:
mtlDepthStencilDescriptor.depthWriteEnabled = false;
break;
case nxt::DepthWriteMode::Enabled:
mtlDepthStencilDescriptor.depthWriteEnabled = true;
break;
default:
ASSERT(false);
break;
}
} }
if (StencilIsEnabled()) { auto& stencil = GetStencil();
if (StencilTestEnabled()) {
MTLStencilDescriptor* backFaceStencil = [MTLStencilDescriptor new]; MTLStencilDescriptor* backFaceStencil = [MTLStencilDescriptor new];
MTLStencilDescriptor* frontFaceStencil = [MTLStencilDescriptor new]; MTLStencilDescriptor* frontFaceStencil = [MTLStencilDescriptor new];
auto& back = GetBackStencil(); backFaceStencil.stencilCompareFunction = MetalDepthStencilCompareFunction(stencil.back.compareFunction);
auto& front = GetFrontStencil(); backFaceStencil.stencilFailureOperation = MetalStencilOperation(stencil.back.stencilFail);
backFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.back.depthFail);
backFaceStencil.depthStencilPassOperation = MetalStencilOperation(stencil.back.depthStencilPass);
backFaceStencil.readMask = stencil.back.mask;
backFaceStencil.writeMask = stencil.back.mask;
backFaceStencil.stencilCompareFunction = DepthStencilCompareFunction(back.compareFunction); frontFaceStencil.stencilCompareFunction = MetalDepthStencilCompareFunction(stencil.front.compareFunction);
backFaceStencil.stencilFailureOperation = StencilOperation(back.stencilFail); frontFaceStencil.stencilFailureOperation = MetalStencilOperation(stencil.front.stencilFail);
backFaceStencil.depthFailureOperation = StencilOperation(back.depthFail); frontFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.front.depthFail);
backFaceStencil.depthStencilPassOperation = StencilOperation(back.stencilPass); frontFaceStencil.depthStencilPassOperation = MetalStencilOperation(stencil.front.depthStencilPass);
backFaceStencil.readMask = back.readMask; frontFaceStencil.readMask = stencil.front.mask;
backFaceStencil.writeMask = back.writeMask; frontFaceStencil.writeMask = stencil.front.mask;
frontFaceStencil.stencilCompareFunction = DepthStencilCompareFunction(front.compareFunction);
frontFaceStencil.stencilFailureOperation = StencilOperation(front.stencilFail);
frontFaceStencil.depthFailureOperation = StencilOperation(front.depthFail);
frontFaceStencil.depthStencilPassOperation = StencilOperation(front.stencilPass);
frontFaceStencil.readMask = front.readMask;
frontFaceStencil.writeMask = front.writeMask;
mtlDepthStencilDescriptor.backFaceStencil = backFaceStencil; mtlDepthStencilDescriptor.backFaceStencil = backFaceStencil;
mtlDepthStencilDescriptor.frontFaceStencil = frontFaceStencil; mtlDepthStencilDescriptor.frontFaceStencil = frontFaceStencil;
@ -758,15 +743,17 @@ namespace metal {
[frontFaceStencil release]; [frontFaceStencil release];
} }
mtlDepthStencilState = [device->GetMTLDevice() newDepthStencilStateWithDescriptor:mtlDepthStencilDescriptor];
[mtlDepthStencilDescriptor release];
} }
DepthStencilState::~DepthStencilState() { DepthStencilState::~DepthStencilState() {
[mtlDepthStencilDescriptor release]; [mtlDepthStencilState release];
mtlDepthStencilDescriptor = nil; mtlDepthStencilState = nil;
} }
MTLDepthStencilDescriptor* DepthStencilState::GetMTLDepthStencilDescriptor() { id<MTLDepthStencilState> DepthStencilState::GetMTLDepthStencilState() {
return mtlDepthStencilDescriptor; return mtlDepthStencilState;
} }
// InputState // InputState
@ -914,24 +901,17 @@ namespace metal {
return; return;
} }
DepthStencilState* depthStencilState = ToBackend(GetDepthStencilState());
MTLDepthStencilDescriptor* dsDesc = depthStencilState->GetMTLDepthStencilDescriptor();
mtlDepthStencilState = [device->GetMTLDevice()
newDepthStencilStateWithDescriptor:dsDesc];
[descriptor release]; [descriptor release];
} }
} }
Pipeline::~Pipeline() { Pipeline::~Pipeline() {
[mtlRenderPipelineState release]; [mtlRenderPipelineState release];
[mtlDepthStencilState release];
[mtlComputePipelineState release]; [mtlComputePipelineState release];
} }
void Pipeline::Encode(id<MTLRenderCommandEncoder> encoder) { void Pipeline::Encode(id<MTLRenderCommandEncoder> encoder) {
ASSERT(!IsCompute()); ASSERT(!IsCompute());
[encoder setDepthStencilState:mtlDepthStencilState];
[encoder setRenderPipelineState:mtlRenderPipelineState]; [encoder setRenderPipelineState:mtlRenderPipelineState];
} }

View File

@ -16,6 +16,7 @@
#include "common/Commands.h" #include "common/Commands.h"
#include "OpenGLBackend.h" #include "OpenGLBackend.h"
#include "PersistentPipelineStateGL.h"
#include "PipelineGL.h" #include "PipelineGL.h"
#include "PipelineLayoutGL.h" #include "PipelineLayoutGL.h"
#include "SamplerGL.h" #include "SamplerGL.h"
@ -26,6 +27,8 @@
namespace backend { namespace backend {
namespace opengl { namespace opengl {
PersistentPipelineState persistentPipelineState;
CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder) CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder)
: CommandBufferBase(builder), device(device), commands(builder->AcquireCommands()) { : CommandBufferBase(builder), device(device), commands(builder->AcquireCommands()) {
} }
@ -144,7 +147,7 @@ namespace opengl {
case Command::SetPipeline: case Command::SetPipeline:
{ {
SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>(); SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
ToBackend(cmd->pipeline)->ApplyNow(); ToBackend(cmd->pipeline)->ApplyNow(persistentPipelineState);
lastPipeline = ToBackend(cmd->pipeline).Get(); lastPipeline = ToBackend(cmd->pipeline).Get();
} }
break; break;
@ -182,7 +185,8 @@ namespace opengl {
{ {
SetStencilReferenceCmd* cmd = commands.NextCommand<SetStencilReferenceCmd>(); SetStencilReferenceCmd* cmd = commands.NextCommand<SetStencilReferenceCmd>();
DepthStencilState* depthStencilState = ToBackend(lastPipeline->GetDepthStencilState()); DepthStencilState* depthStencilState = ToBackend(lastPipeline->GetDepthStencilState());
depthStencilState->ApplyStencilReferenceNow(cmd->backReference, cmd->frontReference); persistentPipelineState.UpdateStencilReference(cmd->reference);
persistentPipelineState.ApplyStencilNow();
} }
break; break;

View File

@ -14,6 +14,7 @@
#include "OpenGLBackend.h" #include "OpenGLBackend.h"
#include "CommandBufferGL.h" #include "CommandBufferGL.h"
#include "PersistentPipelineStateGL.h"
#include "PipelineGL.h" #include "PipelineGL.h"
#include "PipelineLayoutGL.h" #include "PipelineLayoutGL.h"
#include "SamplerGL.h" #include "SamplerGL.h"

View File

@ -45,7 +45,7 @@ namespace opengl {
*device = reinterpret_cast<nxtDevice>(new Device); *device = reinterpret_cast<nxtDevice>(new Device);
} }
static GLuint OpenGLCompareFunction(nxt::CompareFunction compareFunction) { GLuint OpenGLCompareFunction(nxt::CompareFunction compareFunction) {
switch (compareFunction) { switch (compareFunction) {
case nxt::CompareFunction::Never: case nxt::CompareFunction::Never:
return GL_NEVER; return GL_NEVER;
@ -68,7 +68,7 @@ namespace opengl {
} }
} }
static GLuint OpenGLStencilOperation(nxt::StencilOperation stencilOperation) { GLuint OpenGLStencilOperation(nxt::StencilOperation stencilOperation) {
switch (stencilOperation) { switch (stencilOperation) {
case nxt::StencilOperation::Keep: case nxt::StencilOperation::Keep:
return GL_KEEP; return GL_KEEP;
@ -188,69 +188,6 @@ namespace opengl {
DepthStencilState::DepthStencilState(Device* device, DepthStencilStateBuilder* builder) DepthStencilState::DepthStencilState(Device* device, DepthStencilStateBuilder* builder)
: DepthStencilStateBase(builder), device(device) { : DepthStencilStateBase(builder), device(device) {
}
void DepthStencilState::ApplyNow() {
if (DepthIsEnabled()) {
glEnable(GL_DEPTH_TEST);
auto& depth = GetDepth();
glDepthFunc(OpenGLCompareFunction(depth.compareFunction));
switch (depth.depthWriteMode) {
case nxt::DepthWriteMode::Disabled:
glDepthMask(GL_FALSE);
break;
case nxt::DepthWriteMode::Enabled:
glDepthMask(GL_TRUE);
break;
default:
ASSERT(false);
break;
}
}
else {
glDisable(GL_DEPTH_TEST);
}
if (StencilIsEnabled()) {
glEnable(GL_STENCIL_TEST);
auto& back = GetBackStencil();
auto& front = GetFrontStencil();
glStencilOpSeparate(GL_BACK,
OpenGLStencilOperation(back.stencilFail),
OpenGLStencilOperation(back.depthFail),
OpenGLStencilOperation(back.stencilPass)
);
glStencilOpSeparate(GL_FRONT,
OpenGLStencilOperation(front.stencilFail),
OpenGLStencilOperation(front.depthFail),
OpenGLStencilOperation(front.stencilPass)
);
glStencilMaskSeparate(GL_BACK, back.writeMask);
glStencilMaskSeparate(GL_FRONT, front.writeMask);
}
else {
glDisable(GL_STENCIL_TEST);
}
}
void DepthStencilState::ApplyStencilReferenceNow(uint32_t backReference, uint32_t frontReference) {
if (StencilIsEnabled()) {
auto& back = GetBackStencil();
auto& front = GetFrontStencil();
glStencilFuncSeparate(GL_BACK,
OpenGLCompareFunction(back.compareFunction),
backReference,
back.readMask
);
glStencilFuncSeparate(GL_FRONT,
OpenGLCompareFunction(front.compareFunction),
frontReference,
front.readMask
);
}
} }
// InputState // InputState

View File

@ -40,6 +40,7 @@ namespace opengl {
class CommandBuffer; class CommandBuffer;
class DepthStencilState; class DepthStencilState;
class InputState; class InputState;
class PersistentPipelineState;
class Pipeline; class Pipeline;
class PipelineLayout; class PipelineLayout;
class Queue; class Queue;
@ -74,6 +75,9 @@ namespace opengl {
return ToBackendBase<OpenGLBackendTraits>(common); return ToBackendBase<OpenGLBackendTraits>(common);
} }
GLuint OpenGLCompareFunction(nxt::CompareFunction compareFunction);
GLuint OpenGLStencilOperation(nxt::StencilOperation stencilOperation);
// Definition of backend types // Definition of backend types
class Device : public DeviceBase { class Device : public DeviceBase {
public: public:
@ -139,8 +143,6 @@ namespace opengl {
class DepthStencilState : public DepthStencilStateBase { class DepthStencilState : public DepthStencilStateBase {
public: public:
DepthStencilState(Device* device, DepthStencilStateBuilder* builder); DepthStencilState(Device* device, DepthStencilStateBuilder* builder);
void ApplyNow();
void ApplyStencilReferenceNow(uint32_t backReference, uint32_t frontReference);
private: private:
Device* device; Device* device;

View File

@ -0,0 +1,169 @@
// Copyright 2017 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "PersistentPipelineStateGL.h"
#include "OpenGLBackend.h"
namespace backend {
namespace opengl {
PersistentPipelineState::PersistentPipelineState() {
dirtyFields.set(); // initialize all fields as dirty
}
// when a field on PersistentPipelineState::State changes, mark its starting location as dirty
#define SET_FIELD(field, destination, value) { \
if (state.destination != value) { \
dirtyFields.set(field); \
state.destination = value; \
} \
}
void PersistentPipelineState::UpdateDepthStencilInfo(const DepthStencilStateBase* const depthStencilState) {
auto& depth = depthStencilState->GetDepth();
SET_FIELD(DEPTH_COMPARE_FUNCTION, depthInfo.compareFunction, depth.compareFunction)
SET_FIELD(DEPTH_WRITE_ENABLED, depthInfo.depthWriteEnabled, depth.depthWriteEnabled)
SET_FIELD(DEPTH_ENABLED, depthEnabled, depthStencilState->DepthTestEnabled())
auto& stencil = depthStencilState->GetStencil();
SET_FIELD(STENCIL_ENABLED, stencilEnabled, depthStencilState->StencilTestEnabled())
SET_FIELD(STENCIL_BACK_COMPARE_FUNCTION, stencilInfo.back.compareFunction, stencil.back.compareFunction)
SET_FIELD(STENCIL_BACK_STENCIL_FAIL, stencilInfo.back.stencilFail, stencil.back.stencilFail)
SET_FIELD(STENCIL_BACK_DEPTH_FAIL, stencilInfo.back.depthFail, stencil.back.depthFail)
SET_FIELD(STENCIL_BACK_DEPTH_STENCIL_PASS, stencilInfo.back.depthStencilPass, stencil.back.depthStencilPass)
SET_FIELD(STENCIL_BACK_MASK, stencilInfo.back.mask, stencil.back.mask)
SET_FIELD(STENCIL_FRONT_COMPARE_FUNCTION, stencilInfo.front.compareFunction, stencil.front.compareFunction)
SET_FIELD(STENCIL_FRONT_STENCIL_FAIL, stencilInfo.front.stencilFail, stencil.front.stencilFail)
SET_FIELD(STENCIL_FRONT_DEPTH_FAIL, stencilInfo.front.depthFail, stencil.front.depthFail)
SET_FIELD(STENCIL_FRONT_DEPTH_STENCIL_PASS, stencilInfo.front.depthStencilPass, stencil.front.depthStencilPass)
SET_FIELD(STENCIL_FRONT_MASK, stencilInfo.front.mask, stencil.front.mask)
}
void PersistentPipelineState::UpdateStencilReference(uint32_t stencilReference) {
SET_FIELD(STENCIL_REFERENCE, stencilReference, stencilReference)
}
#undef SET_FIELD
bool PersistentPipelineState::IsDirty(Field field) const {
return dirtyFields.test(field);
}
void PersistentPipelineState::CleanField(Field field) {
dirtyFields.reset(field);
}
void PersistentPipelineState::ApplyDepthNow() {
if (IsDirty(DEPTH_ENABLED)) {
if (state.depthEnabled) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
CleanField(DEPTH_ENABLED);
}
if (IsDirty(DEPTH_WRITE_ENABLED)) {
if (state.depthInfo.depthWriteEnabled) {
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
}
CleanField(DEPTH_WRITE_ENABLED);
}
if (IsDirty(DEPTH_COMPARE_FUNCTION)) {
glDepthFunc(OpenGLCompareFunction(state.depthInfo.compareFunction));
CleanField(DEPTH_COMPARE_FUNCTION);
}
}
void PersistentPipelineState::ApplyStencilNow() {
if (IsDirty(STENCIL_ENABLED)) {
if (state.stencilEnabled) {
glEnable(GL_STENCIL_TEST);
} else {
glDisable(GL_STENCIL_TEST);
}
CleanField(STENCIL_ENABLED);
}
if (IsDirty(STENCIL_BACK_STENCIL_FAIL) ||
IsDirty(STENCIL_BACK_DEPTH_FAIL) ||
IsDirty(STENCIL_BACK_DEPTH_STENCIL_PASS)) {
glStencilOpSeparate(GL_BACK,
OpenGLStencilOperation(state.stencilInfo.back.stencilFail),
OpenGLStencilOperation(state.stencilInfo.back.depthFail),
OpenGLStencilOperation(state.stencilInfo.back.depthStencilPass)
);
CleanField(STENCIL_BACK_STENCIL_FAIL);
CleanField(STENCIL_BACK_DEPTH_FAIL);
CleanField(STENCIL_BACK_DEPTH_STENCIL_PASS);
}
if (IsDirty(STENCIL_BACK_COMPARE_FUNCTION) ||
IsDirty(STENCIL_REFERENCE) ||
IsDirty(STENCIL_BACK_MASK)) {
glStencilFuncSeparate(GL_BACK,
OpenGLCompareFunction(state.stencilInfo.back.compareFunction),
state.stencilReference,
state.stencilInfo.back.mask
);
if (IsDirty(STENCIL_BACK_MASK)) {
glStencilMaskSeparate(GL_BACK, state.stencilInfo.back.mask);
}
CleanField(STENCIL_BACK_COMPARE_FUNCTION);
CleanField(STENCIL_BACK_MASK);
}
if (IsDirty(STENCIL_FRONT_STENCIL_FAIL) ||
IsDirty(STENCIL_FRONT_DEPTH_FAIL) ||
IsDirty(STENCIL_FRONT_DEPTH_STENCIL_PASS)) {
glStencilOpSeparate(GL_FRONT,
OpenGLStencilOperation(state.stencilInfo.front.stencilFail),
OpenGLStencilOperation(state.stencilInfo.front.depthFail),
OpenGLStencilOperation(state.stencilInfo.front.depthStencilPass)
);
CleanField(STENCIL_FRONT_STENCIL_FAIL);
CleanField(STENCIL_FRONT_DEPTH_FAIL);
CleanField(STENCIL_FRONT_DEPTH_STENCIL_PASS);
}
if (IsDirty(STENCIL_FRONT_COMPARE_FUNCTION) ||
IsDirty(STENCIL_REFERENCE) ||
IsDirty(STENCIL_FRONT_MASK)) {
glStencilFuncSeparate(GL_FRONT,
OpenGLCompareFunction(state.stencilInfo.front.compareFunction),
state.stencilReference,
state.stencilInfo.front.mask
);
if (IsDirty(STENCIL_FRONT_MASK)) {
glStencilMaskSeparate(GL_FRONT, state.stencilInfo.front.mask);
}
CleanField(STENCIL_FRONT_COMPARE_FUNCTION);
CleanField(STENCIL_FRONT_MASK);
}
CleanField(STENCIL_REFERENCE); // clean this last because its used for both the back and front functions
}
}
}

View File

@ -0,0 +1,72 @@
// Copyright 2017 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef BACKEND_OPENGL_PERSISTENTPIPELINESTATE_H_
#define BACKEND_OPENGL_PERSISTENTPIPELINESTATE_H_
#include "common/DepthStencilState.h"
#include <bitset>
namespace backend {
namespace opengl {
class PersistentPipelineState {
public:
PersistentPipelineState();
void UpdateDepthStencilInfo(const DepthStencilStateBase* const depthStencilState);
void UpdateStencilReference(uint32_t stencilReference);
void ApplyDepthNow();
void ApplyStencilNow();
enum Field {
DEPTH_COMPARE_FUNCTION,
DEPTH_WRITE_ENABLED,
DEPTH_ENABLED,
STENCIL_ENABLED,
STENCIL_BACK_COMPARE_FUNCTION,
STENCIL_BACK_STENCIL_FAIL,
STENCIL_BACK_DEPTH_FAIL,
STENCIL_BACK_DEPTH_STENCIL_PASS,
STENCIL_BACK_MASK,
STENCIL_FRONT_COMPARE_FUNCTION,
STENCIL_FRONT_STENCIL_FAIL,
STENCIL_FRONT_DEPTH_FAIL,
STENCIL_FRONT_DEPTH_STENCIL_PASS,
STENCIL_FRONT_MASK,
STENCIL_REFERENCE,
Count
};
struct State {
bool depthEnabled;
bool stencilEnabled;
DepthStencilStateBase::DepthInfo depthInfo;
DepthStencilStateBase::StencilInfo stencilInfo;
uint32_t stencilReference;
};
private:
State state;
std::bitset<Field::Count> dirtyFields;
inline bool IsDirty(Field field) const;
inline void CleanField(Field field);
};
}
}
#endif // BACKEND_OPENGL_PERSISTENTPIPELINESTATE_H_

View File

@ -15,6 +15,7 @@
#include "PipelineGL.h" #include "PipelineGL.h"
#include "OpenGLBackend.h" #include "OpenGLBackend.h"
#include "PersistentPipelineStateGL.h"
#include "PipelineLayoutGL.h" #include "PipelineLayoutGL.h"
#include "ShaderModuleGL.h" #include "ShaderModuleGL.h"
@ -202,13 +203,15 @@ namespace opengl {
return program; return program;
} }
void Pipeline::ApplyNow() { void Pipeline::ApplyNow(PersistentPipelineState &persistentPipelineState) {
glUseProgram(program); glUseProgram(program);
auto inputState = ToBackend(GetInputState()); auto inputState = ToBackend(GetInputState());
glBindVertexArray(inputState->GetVAO()); glBindVertexArray(inputState->GetVAO());
auto depthStencilState = ToBackend(GetDepthStencilState());
depthStencilState->ApplyNow(); persistentPipelineState.UpdateDepthStencilInfo(GetDepthStencilState());
persistentPipelineState.ApplyDepthNow();
persistentPipelineState.ApplyStencilNow();
} }
} }

View File

@ -25,6 +25,7 @@ namespace backend {
namespace opengl { namespace opengl {
class Device; class Device;
class PersistentPipelineState;
class ShaderModule; class ShaderModule;
class Pipeline : public PipelineBase { class Pipeline : public PipelineBase {
@ -39,7 +40,7 @@ namespace opengl {
const std::vector<GLuint>& GetTextureUnitsForTexture(GLuint index) const; const std::vector<GLuint>& GetTextureUnitsForTexture(GLuint index) const;
GLuint GetProgramHandle() const; GLuint GetProgramHandle() const;
void ApplyNow(); void ApplyNow(PersistentPipelineState &persistentPipelineState);
private: private:
GLuint program; GLuint program;