mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
metal: implement depth/stencil state
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -195,6 +195,7 @@ private:
|
||||
Texture *defaultTextures[TEXTURE_MAX_ENUM];
|
||||
|
||||
std::map<uint64, void *> cachedSamplers;
|
||||
std::unordered_map<uint64, void *> cachedDepthStencilStates;
|
||||
|
||||
}; // Graphics
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user