metal: implement depth/stencil state

This commit is contained in:
Alex Szpakowski
2020-06-14 21:14:56 -03:00
parent 9d2dca5740
commit 9aa9319eb5
9 changed files with 121 additions and 70 deletions
+18 -6
View File
@@ -144,7 +144,6 @@ Graphics::Graphics()
, pixelHeight(0)
, created(false)
, active(true)
, writingToStencil(false)
, batchedDrawState()
, projectionMatrix()
, renderTargetSwitchCount(0)
@@ -420,7 +419,12 @@ void Graphics::restoreState(const DisplayState &s)
else
setScissor();
setStencilTest(s.stencilCompare, s.stencilTestValue);
if (s.stencil.action != STENCIL_KEEP)
drawToStencilBuffer(s.stencil.action, s.stencil.value);
else
stopDrawToStencilBuffer();
setStencilTest(s.stencil.compare, s.stencil.value);
setDepthMode(s.depthTest, s.depthWrite);
setMeshCullMode(s.meshCullMode);
@@ -464,8 +468,16 @@ void Graphics::restoreStateChecked(const DisplayState &s)
setScissor();
}
if (s.stencilCompare != cur.stencilCompare || s.stencilTestValue != cur.stencilTestValue)
setStencilTest(s.stencilCompare, s.stencilTestValue);
if (s.stencil.action != cur.stencil.action)
{
if (s.stencil.action != STENCIL_KEEP)
drawToStencilBuffer(s.stencil.action, s.stencil.value);
else
stopDrawToStencilBuffer();
}
if (s.stencil.compare != cur.stencil.compare || s.stencil.value != cur.stencil.value)
setStencilTest(s.stencil.compare, s.stencil.value);
if (s.depthTest != cur.depthTest || s.depthWrite != cur.depthWrite)
setDepthMode(s.depthTest, s.depthWrite);
@@ -903,8 +915,8 @@ void Graphics::setStencilTest()
void Graphics::getStencilTest(CompareMode &compare, int &value) const
{
const DisplayState &state = states.back();
compare = state.stencilCompare;
value = state.stencilTestValue;
compare = state.stencil.compare;
value = state.stencil.value;
}
void Graphics::setDepthMode()
+1 -4
View File
@@ -898,8 +898,7 @@ protected:
bool scissor = false;
Rect scissorRect = Rect();
CompareMode stencilCompare = COMPARE_ALWAYS;
int stencilTestValue = 0;
StencilState stencil;
CompareMode depthTest = COMPARE_ALWAYS;
bool depthWrite = false;
@@ -981,8 +980,6 @@ protected:
bool created;
bool active;
bool writingToStencil;
StrongRef<love::graphics::Font> defaultFont;
std::vector<ScreenshotInfo> pendingScreenshotCallbacks;
+1
View File
@@ -195,6 +195,7 @@ private:
Texture *defaultTextures[TEXTURE_MAX_ENUM];
std::map<uint64, void *> cachedSamplers;
std::unordered_map<uint64, void *> cachedDepthStencilStates;
}; // Graphics
+85 -29
View File
@@ -95,6 +95,23 @@ static MTLCompareFunction getMTLCompareFunction(CompareMode mode)
return MTLCompareFunctionNever;
}
static MTLStencilOperation getMTLStencilOperation(StencilAction action)
{
switch (action)
{
case STENCIL_KEEP: return MTLStencilOperationKeep;
case STENCIL_ZERO: return MTLStencilOperationZero;
case STENCIL_REPLACE: return MTLStencilOperationReplace;
case STENCIL_INCREMENT: return MTLStencilOperationIncrementClamp;
case STENCIL_DECREMENT: return MTLStencilOperationDecrementClamp;
case STENCIL_INCREMENT_WRAP: return MTLStencilOperationIncrementWrap;
case STENCIL_DECREMENT_WRAP: return MTLStencilOperationDecrementWrap;
case STENCIL_INVERT: return MTLStencilOperationInvert;
case STENCIL_MAX_ENUM: return MTLStencilOperationKeep;
}
return MTLStencilOperationKeep;
}
love::graphics::Graphics *createInstance()
{
love::graphics::Graphics *instance = nullptr;
@@ -192,6 +209,9 @@ Graphics::~Graphics()
for (auto &kvp : cachedSamplers)
CFBridgingRelease(kvp.second);
for (auto &kvp : cachedDepthStencilStates)
CFBridgingRelease(kvp.second);
graphicsInstance = nullptr;
}}
@@ -433,29 +453,38 @@ id<MTLSamplerState> Graphics::getCachedSampler(const SamplerState &s)
id<MTLDepthStencilState> Graphics::getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil)
{
id<MTLDepthStencilState> state = nil;
uint64 key = (depth.compare << 0) | ((uint32)depth.write << 8)
| (stencil.action << 16) | (stencil.compare << 24)
| ((uint64)std::max(0, std::min(255, stencil.value)) << 32)
| ((uint64)std::min(255u, stencil.readMask) << 40)
| ((uint64)std::min(255u, stencil.writeMask) << 48);
{
MTLStencilDescriptor *stencildesc = [MTLStencilDescriptor new];
auto it = cachedDepthStencilStates.find(key);
if (it != cachedDepthStencilStates.end())
return (__bridge id<MTLDepthStencilState>) it->second;
stencildesc.stencilCompareFunction = getMTLCompareFunction(stencil.compare);
stencildesc.stencilFailureOperation = MTLStencilOperationKeep;
stencildesc.depthFailureOperation = MTLStencilOperationKeep;
stencildesc.depthStencilPassOperation = MTLStencilOperationKeep; // TODO
stencildesc.readMask = stencil.readMask;
stencildesc.writeMask = stencil.writeMask;
MTLStencilDescriptor *stencildesc = [MTLStencilDescriptor new];
MTLDepthStencilDescriptor *desc = [MTLDepthStencilDescriptor new];
stencildesc.stencilCompareFunction = getMTLCompareFunction(stencil.compare);
stencildesc.stencilFailureOperation = MTLStencilOperationKeep;
stencildesc.depthFailureOperation = MTLStencilOperationKeep;
stencildesc.depthStencilPassOperation = getMTLStencilOperation(stencil.action);
stencildesc.readMask = stencil.readMask;
stencildesc.writeMask = stencil.writeMask;
desc.depthCompareFunction = getMTLCompareFunction(depth.compare);
desc.depthWriteEnabled = depth.write;
desc.frontFaceStencil = stencildesc;
desc.backFaceStencil = stencildesc;
MTLDepthStencilDescriptor *desc = [MTLDepthStencilDescriptor new];
state = [device newDepthStencilStateWithDescriptor:desc];
}
desc.depthCompareFunction = getMTLCompareFunction(depth.compare);
desc.depthWriteEnabled = depth.write;
desc.frontFaceStencil = stencildesc;
desc.backFaceStencil = stencildesc;
return state;
id<MTLDepthStencilState> mtlstate = [device newDepthStencilStateWithDescriptor:desc];
if (mtlstate != nil)
cachedDepthStencilStates[key] = (void *) CFBridgingRetain(mtlstate);
return mtlstate;
}
void Graphics::applyRenderState(id<MTLRenderCommandEncoder> encoder, const vertex::Attributes &attributes)
@@ -559,7 +588,22 @@ void Graphics::applyRenderState(id<MTLRenderCommandEncoder> encoder, const verte
if (dirtyState & (STATEBIT_DEPTH | STATEBIT_STENCIL))
{
// id<MTLDepthStencilState> dsstate = getCachedDepthStencilState(<#const DepthState &depth#>, <#const StencilState &stencil#>)
DepthState depth;
depth.compare = state.depthTest;
depth.write = state.depthWrite;
StencilState stencil = state.stencil;
if (stencil.action != STENCIL_KEEP)
{
// FIXME
stencil.compare = COMPARE_ALWAYS;
}
id<MTLDepthStencilState> mtlstate = getCachedDepthStencilState(depth, stencil);
[encoder setDepthStencilState:mtlstate];
[encoder setStencilReferenceValue:state.stencil.value];
}
dirtyRenderState = 0;
@@ -888,8 +932,8 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
auto color = MTLClearColorMake(c.value.r, c.value.g, c.value.b, c.value.a);
for (int i = 0; i < MAX_COLOR_RENDER_TARGETS; i++)
{
passDesc.colorAttachments[0].clearColor = color;
passDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
passDesc.colorAttachments[i].clearColor = color;
passDesc.colorAttachments[i].loadAction = MTLLoadActionClear;
}
}
@@ -1098,7 +1142,8 @@ void Graphics::setScissor()
void Graphics::drawToStencilBuffer(StencilAction action, int value)
{
const auto &rts = states.back().renderTargets;
DisplayState &state = states.back();
const auto &rts = state.renderTargets;
love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
if (!isRenderTargetActive() && !windowHasStencil)
@@ -1108,7 +1153,8 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value)
flushBatchedDraws();
writingToStencil = true;
state.stencil.action = action;
state.stencil.value = value;
dirtyRenderState |= STATEBIT_STENCIL;
// TODO
@@ -1116,20 +1162,20 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value)
void Graphics::stopDrawToStencilBuffer()
{
if (!writingToStencil)
DisplayState &state = states.back();
if (state.stencil.action == STENCIL_KEEP)
return;
flushBatchedDraws();
writingToStencil = false;
const DisplayState &state = states.back();
state.stencil.action = STENCIL_KEEP;
// Revert the color write mask.
setColorMask(state.colorMask);
// Use the user-set stencil test state when writes are disabled.
setStencilTest(state.stencilCompare, state.stencilTestValue);
setStencilTest(state.stencil.compare, state.stencil.value);
dirtyRenderState |= STATEBIT_STENCIL;
}
@@ -1146,12 +1192,22 @@ void Graphics::setDepthMode(CompareMode compare, bool write)
void Graphics::setFrontFaceWinding(vertex::Winding winding)
{
// TODO
if (states.back().winding != winding)
{
flushBatchedDraws();
states.back().winding = winding;
dirtyRenderState |= STATEBIT_FACEWINDING;
}
}
void Graphics::setColorMask(ColorChannelMask mask)
{
// TODO
if (states.back().colorMask != mask)
{
flushBatchedDraws();
states.back().colorMask = mask;
dirtyRenderState |= STATEBIT_COLORMASK;
}
}
void Graphics::setBlendState(const BlendState &blend)
-2
View File
@@ -361,9 +361,7 @@ id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(const RenderPipelineK
{
MTLVertexDescriptor *vertdesc = [MTLVertexDescriptor vertexDescriptor];
const auto &attributes = key.vertexAttributes;
uint32 allbits = attributes.enableBits;
for (const auto &pair : this->attributes)
{
+13 -11
View File
@@ -1119,7 +1119,8 @@ void Graphics::setScissor()
void Graphics::drawToStencilBuffer(StencilAction action, int value)
{
const auto &rts = states.back().renderTargets;
DisplayState &state = states.back();
const auto &rts = state.renderTargets;
love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
if (!isRenderTargetActive() && !windowHasStencil)
@@ -1129,7 +1130,8 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value)
flushBatchedDraws();
writingToStencil = true;
state.stencil.action = action;
state.stencil.value = value;
// Disable color writes but don't save the state for it.
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -1169,33 +1171,33 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value)
void Graphics::stopDrawToStencilBuffer()
{
if (!writingToStencil)
DisplayState &state = states.back();
if (state.stencil.action == STENCIL_KEEP)
return;
flushBatchedDraws();
writingToStencil = false;
const DisplayState &state = states.back();
state.stencil.action = STENCIL_KEEP;
// Revert the color write mask.
setColorMask(state.colorMask);
// Use the user-set stencil test state when writes are disabled.
setStencilTest(state.stencilCompare, state.stencilTestValue);
setStencilTest(state.stencil.compare, state.stencil.value);
}
void Graphics::setStencilTest(CompareMode compare, int value)
{
DisplayState &state = states.back();
if (state.stencilCompare != compare || state.stencilTestValue != value)
if (state.stencil.compare != compare || state.stencil.value != value)
flushBatchedDraws();
state.stencilCompare = compare;
state.stencilTestValue = value;
state.stencil.compare = compare;
state.stencil.value = value;
if (writingToStencil)
if (state.stencil.action != STENCIL_KEEP)
return;
if (compare == COMPARE_ALWAYS)
-10
View File
@@ -42,7 +42,6 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
, program(0)
, builtinUniforms()
, builtinUniformInfo()
, builtinAttributes()
, lastPointSize(0.0f)
{
// load shader source and create program object
@@ -343,15 +342,6 @@ bool Shader::loadVolatile()
// Get all active uniform variables in this shader from OpenGL.
mapActiveUniforms();
for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
{
const char *name = nullptr;
if (vertex::getConstant(BuiltinVertexAttribute(i), name))
builtinAttributes[i] = glGetAttribLocation(program, name);
else
builtinAttributes[i] = -1;
}
if (current == this)
{
// make sure glUseProgram gets called.
-3
View File
@@ -102,9 +102,6 @@ private:
GLint builtinUniforms[BUILTIN_MAX_ENUM];
UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
// Location values for any generic vertex attribute variables.
GLint builtinAttributes[ATTRIB_MAX_ENUM];
std::map<std::string, GLint> attributes;
// Uniform location buffer map
+3 -5
View File
@@ -78,7 +78,7 @@ GLSL.UNIFORMS = [[
// We *really* don't want to use mediump for these in vertex shaders though.
#ifdef LOVE_USE_UNIFORM_BUFFERS
layout (std140) uniform love_UniformsPerDrawBuffer {
LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
highp vec4 love_UniformsPerDraw[13];
};
#else
uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
@@ -102,7 +102,6 @@ LOVE_HIGHP_OR_MEDIUMP vec4 ConstantColor;
#define ViewNormalFromLocal NormalMatrix
void love_initializeBuiltinUniforms() {
#if 1
TransformMatrix = mat4(
love_UniformsPerDraw[0],
love_UniformsPerDraw[1],
@@ -125,7 +124,6 @@ void love_initializeBuiltinUniforms() {
love_ScreenSize = love_UniformsPerDraw[11];
ConstantColor = love_UniformsPerDraw[12];
#endif
}
]]
@@ -394,8 +392,8 @@ local function isPixelCode(code)
if code:match("vec4%s+effect%s*%(") then
return true
elseif code:match("void%s+effect%s*%(") then -- custom effect function
local multirendertargets = (code:match("love_RenderTargets") ~= nil) or (code:match("love_Canvases") ~= nil)
return true, true, multirendertargets
local mrt = (code:match("love_RenderTargets") ~= nil) or (code:match("love_Canvases") ~= nil)
return true, true, mrt
else
return false
end