diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index c0a6b3e09..61ce88e60 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -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() diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index a76a81400..fa606ac11 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -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 defaultFont; std::vector pendingScreenshotCallbacks; diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index b664d7117..76272a9ab 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -195,6 +195,7 @@ private: Texture *defaultTextures[TEXTURE_MAX_ENUM]; std::map cachedSamplers; + std::unordered_map cachedDepthStencilStates; }; // Graphics diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index 096834ff1..614fc71a2 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -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 Graphics::getCachedSampler(const SamplerState &s) id Graphics::getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil) { - id 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) 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 mtlstate = [device newDepthStencilStateWithDescriptor:desc]; + + if (mtlstate != nil) + cachedDepthStencilStates[key] = (void *) CFBridgingRetain(mtlstate); + + return mtlstate; } void Graphics::applyRenderState(id encoder, const vertex::Attributes &attributes) @@ -559,7 +588,22 @@ void Graphics::applyRenderState(id encoder, const verte if (dirtyState & (STATEBIT_DEPTH | STATEBIT_STENCIL)) { -// id 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 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) diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index 49f339153..542a11bf0 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -361,9 +361,7 @@ id Shader::getCachedRenderPipeline(const RenderPipelineK { MTLVertexDescriptor *vertdesc = [MTLVertexDescriptor vertexDescriptor]; - const auto &attributes = key.vertexAttributes; - uint32 allbits = attributes.enableBits; for (const auto &pair : this->attributes) { diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 8a5c178ff..62d6bac9a 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -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) diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index e9c1335d9..60c1c8d17 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -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. diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 868563970..d412b5136 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -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 attributes; // Uniform location buffer map diff --git a/src/modules/graphics/wrap_GraphicsShader.lua b/src/modules/graphics/wrap_GraphicsShader.lua index 3c74e63e7..03b057c08 100644 --- a/src/modules/graphics/wrap_GraphicsShader.lua +++ b/src/modules/graphics/wrap_GraphicsShader.lua @@ -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