mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
metal: avoid redundant resource binding calls.
This commit is contained in:
@@ -145,6 +145,57 @@ static inline id<MTLBuffer> getMTLBuffer(love::graphics::Resource *res)
|
||||
return res ? (__bridge id<MTLBuffer>)(void *) res->getHandle() : nil;
|
||||
}
|
||||
|
||||
static inline void setBuffer(id<MTLRenderCommandEncoder> encoder, Graphics::RenderEncoderBindings &bindings, ShaderStage::StageType stage, int index, id<MTLBuffer> buffer, size_t offset)
|
||||
{
|
||||
void *b = (__bridge void *)buffer;
|
||||
auto &binding = bindings.buffers[index][stage];
|
||||
if (binding.buffer != b)
|
||||
{
|
||||
binding.buffer = b;
|
||||
binding.offset = offset;
|
||||
if (stage == ShaderStage::STAGE_VERTEX)
|
||||
[encoder setVertexBuffer:buffer offset:offset atIndex:index];
|
||||
else if (stage == ShaderStage::STAGE_PIXEL)
|
||||
[encoder setFragmentBuffer:buffer offset:offset atIndex:index];
|
||||
}
|
||||
else if (binding.offset != offset)
|
||||
{
|
||||
binding.offset = offset;
|
||||
if (stage == ShaderStage::STAGE_VERTEX)
|
||||
[encoder setVertexBufferOffset:offset atIndex:index];
|
||||
else if (stage == ShaderStage::STAGE_PIXEL)
|
||||
[encoder setFragmentBufferOffset:offset atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setTexture(id<MTLRenderCommandEncoder> encoder, Graphics::RenderEncoderBindings &bindings, ShaderStage::StageType stage, int index, id<MTLTexture> texture)
|
||||
{
|
||||
void *t = (__bridge void *)texture;
|
||||
auto &binding = bindings.textures[index][stage];
|
||||
if (binding != t)
|
||||
{
|
||||
binding = t;
|
||||
if (stage == ShaderStage::STAGE_VERTEX)
|
||||
[encoder setVertexTexture:texture atIndex:index];
|
||||
else if (stage == ShaderStage::STAGE_PIXEL)
|
||||
[encoder setFragmentTexture:texture atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setSampler(id<MTLRenderCommandEncoder> encoder, Graphics::RenderEncoderBindings &bindings, ShaderStage::StageType stage, int index, id<MTLSamplerState> sampler)
|
||||
{
|
||||
void *s = (__bridge void *)sampler;
|
||||
auto &binding = bindings.samplers[index][stage];
|
||||
if (binding != s)
|
||||
{
|
||||
binding = s;
|
||||
if (stage == ShaderStage::STAGE_VERTEX)
|
||||
[encoder setVertexSamplerState:sampler atIndex:index];
|
||||
else if (stage == ShaderStage::STAGE_PIXEL)
|
||||
[encoder setFragmentSamplerState:sampler atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
love::graphics::Graphics *createInstance()
|
||||
{
|
||||
love::graphics::Graphics *instance = nullptr;
|
||||
@@ -182,6 +233,7 @@ Graphics::Graphics()
|
||||
, windowHasStencil(false)
|
||||
, requestedBackbufferMSAA(0)
|
||||
, attachmentStoreActions()
|
||||
, renderBindings()
|
||||
, uniformBufferOffset(0)
|
||||
, defaultAttributesBuffer(nullptr)
|
||||
, defaultTextures()
|
||||
@@ -226,6 +278,35 @@ Graphics::Graphics()
|
||||
defaultTextures[i]->replacePixels(defaultpixel, sizeof(defaultpixel), 0, 0, r, false);
|
||||
}
|
||||
|
||||
if (batchedDrawState.vb[0] == nullptr)
|
||||
{
|
||||
// Initial sizes that should be good enough for most cases. It will
|
||||
// resize to fit if needed, later.
|
||||
batchedDrawState.vb[0] = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
||||
batchedDrawState.vb[1] = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
||||
batchedDrawState.indexBuffer = CreateStreamBuffer(device, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
}
|
||||
|
||||
createQuadIndexBuffer();
|
||||
|
||||
// We always need a default shader.
|
||||
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
|
||||
{
|
||||
auto stype = (Shader::StandardShader) i;
|
||||
if (!Shader::standardShaders[i])
|
||||
{
|
||||
std::vector<std::string> stages;
|
||||
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_VERTEX));
|
||||
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_PIXEL));
|
||||
Shader::standardShaders[i] = newShader(stages);
|
||||
}
|
||||
}
|
||||
|
||||
// A shader should always be active, but the default shader shouldn't be
|
||||
// returned by getShader(), so we don't do setShader(defaultShader).
|
||||
if (!Shader::current)
|
||||
Shader::standardShaders[Shader::STANDARD_DEFAULT]->attach();
|
||||
|
||||
auto window = Module::getInstance<love::window::Window>(M_WINDOW);
|
||||
|
||||
if (window != nullptr)
|
||||
@@ -347,38 +428,9 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
|
||||
created = true;
|
||||
|
||||
if (batchedDrawState.vb[0] == nullptr)
|
||||
{
|
||||
// Initial sizes that should be good enough for most cases. It will
|
||||
// resize to fit if needed, later.
|
||||
batchedDrawState.vb[0] = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
||||
batchedDrawState.vb[1] = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
||||
batchedDrawState.indexBuffer = CreateStreamBuffer(device, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
}
|
||||
|
||||
createQuadIndexBuffer();
|
||||
|
||||
// Restore the graphics state.
|
||||
restoreState(states.back());
|
||||
|
||||
// We always need a default shader.
|
||||
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
|
||||
{
|
||||
auto stype = (Shader::StandardShader) i;
|
||||
if (!Shader::standardShaders[i])
|
||||
{
|
||||
std::vector<std::string> stages;
|
||||
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_VERTEX));
|
||||
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_PIXEL));
|
||||
Shader::standardShaders[i] = newShader(stages);
|
||||
}
|
||||
}
|
||||
|
||||
// A shader should always be active, but the default shader shouldn't be
|
||||
// returned by getShader(), so we don't do setShader(defaultShader).
|
||||
if (!Shader::current)
|
||||
Shader::standardShaders[Shader::STANDARD_DEFAULT]->attach();
|
||||
|
||||
return true;
|
||||
}}
|
||||
|
||||
@@ -441,7 +493,7 @@ void Graphics::submitCommandBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setAttachment(const Graphics::RenderTarget &rt, MTLRenderPassAttachmentDescriptor *desc, MTLStoreAction &storeaction)
|
||||
static inline void setAttachment(const Graphics::RenderTarget &rt, MTLRenderPassAttachmentDescriptor *desc, MTLStoreAction &storeaction, bool setload = true)
|
||||
{
|
||||
bool isvolume = rt.texture->getTextureType() == TEXTURE_VOLUME;
|
||||
|
||||
@@ -450,8 +502,12 @@ static inline void setAttachment(const Graphics::RenderTarget &rt, MTLRenderPass
|
||||
desc.slice = isvolume ? 0 : rt.slice;
|
||||
desc.depthPlane = isvolume ? rt.slice : 0;
|
||||
|
||||
// Default to load until clear or discard is called.
|
||||
desc.loadAction = MTLLoadActionLoad;
|
||||
if (setload)
|
||||
{
|
||||
// Default to load until clear or discard is called.
|
||||
desc.loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
|
||||
desc.storeAction = MTLStoreActionUnknown;
|
||||
storeaction = MTLStoreActionStore;
|
||||
|
||||
@@ -504,14 +560,16 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
|
||||
passDesc.colorAttachments[0].depthPlane = 0;
|
||||
|
||||
RenderTarget rt(backbufferDepthStencil);
|
||||
setAttachment(rt, passDesc.depthAttachment, attachmentStoreActions.depth);
|
||||
setAttachment(rt, passDesc.stencilAttachment, attachmentStoreActions.stencil);
|
||||
setAttachment(rt, passDesc.depthAttachment, attachmentStoreActions.depth, false);
|
||||
setAttachment(rt, passDesc.stencilAttachment, attachmentStoreActions.stencil, false);
|
||||
attachmentStoreActions.depth = MTLStoreActionDontCare;
|
||||
attachmentStoreActions.stencil = MTLStoreActionDontCare;
|
||||
}
|
||||
|
||||
renderEncoder = [useCommandBuffer() renderCommandEncoderWithDescriptor:passDesc];
|
||||
|
||||
renderBindings = {};
|
||||
|
||||
for (int i = 0; i < MAX_COLOR_RENDER_TARGETS; i++)
|
||||
{
|
||||
passDesc.colorAttachments[0].texture = nil;
|
||||
@@ -524,7 +582,7 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
|
||||
passDesc.stencilAttachment.resolveTexture = nil;
|
||||
|
||||
id<MTLBuffer> defaultbuffer = getMTLBuffer(defaultAttributesBuffer);
|
||||
[renderEncoder setVertexBuffer:defaultbuffer offset:0 atIndex:DEFAULT_VERTEX_BUFFER_BINDING];
|
||||
setBuffer(renderEncoder, renderBindings, ShaderStage::STAGE_VERTEX, DEFAULT_VERTEX_BUFFER_BINDING, defaultbuffer, 0);
|
||||
|
||||
dirtyRenderState = STATEBIT_ALL;
|
||||
}
|
||||
@@ -850,8 +908,9 @@ void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, lo
|
||||
id<MTLBuffer> buffer = getMTLBuffer(uniformBuffer);
|
||||
int uniformindex = Shader::getUniformBufferBinding();
|
||||
|
||||
[renderEncoder setVertexBuffer:buffer offset:uniformBufferOffset atIndex:uniformindex];
|
||||
[renderEncoder setFragmentBuffer:buffer offset:uniformBufferOffset atIndex:uniformindex];
|
||||
auto &bindings = renderBindings;
|
||||
setBuffer(renderEncoder, bindings, ShaderStage::STAGE_VERTEX, uniformindex, buffer, uniformBufferOffset);
|
||||
setBuffer(renderEncoder, bindings, ShaderStage::STAGE_PIXEL, uniformindex, buffer, uniformBufferOffset);
|
||||
|
||||
uniformBufferOffset += alignUp(size, alignment);
|
||||
|
||||
@@ -873,25 +932,25 @@ void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, lo
|
||||
sampler = getMTLSampler(maintex);
|
||||
}
|
||||
|
||||
uint8 texindex = b.texturestages[ShaderStage::STAGE_VERTEX];
|
||||
uint8 sampindex = b.samplerstages[ShaderStage::STAGE_VERTEX];
|
||||
uint8 texindex = b.textureStages[ShaderStage::STAGE_VERTEX];
|
||||
uint8 sampindex = b.samplerStages[ShaderStage::STAGE_VERTEX];
|
||||
|
||||
if (texindex != LOVE_UINT8_MAX)
|
||||
[renderEncoder setVertexTexture:texture atIndex:texindex];
|
||||
setTexture(renderEncoder, bindings, ShaderStage::STAGE_VERTEX, texindex, texture);
|
||||
if (sampindex != LOVE_UINT8_MAX)
|
||||
[renderEncoder setVertexSamplerState:sampler atIndex:sampindex];
|
||||
setSampler(renderEncoder, bindings, ShaderStage::STAGE_VERTEX, sampindex, sampler);
|
||||
|
||||
texindex = b.texturestages[ShaderStage::STAGE_PIXEL];
|
||||
sampindex = b.samplerstages[ShaderStage::STAGE_PIXEL];
|
||||
texindex = b.textureStages[ShaderStage::STAGE_PIXEL];
|
||||
sampindex = b.samplerStages[ShaderStage::STAGE_PIXEL];
|
||||
|
||||
if (texindex != LOVE_UINT8_MAX)
|
||||
[renderEncoder setFragmentTexture:texture atIndex:texindex];
|
||||
setTexture(renderEncoder, bindings, ShaderStage::STAGE_PIXEL, texindex, texture);
|
||||
if (sampindex != LOVE_UINT8_MAX)
|
||||
[renderEncoder setFragmentSamplerState:sampler atIndex:sampindex];
|
||||
setSampler(renderEncoder, bindings, ShaderStage::STAGE_PIXEL, sampindex, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
static void setVertexBuffers(id<MTLRenderCommandEncoder> encoder, const BufferBindings *buffers)
|
||||
static void setVertexBuffers(id<MTLRenderCommandEncoder> encoder, const BufferBindings *buffers, Graphics::RenderEncoderBindings &bindings)
|
||||
{
|
||||
uint32 allbits = buffers->useBits;
|
||||
uint32 i = 0;
|
||||
@@ -903,7 +962,7 @@ static void setVertexBuffers(id<MTLRenderCommandEncoder> encoder, const BufferBi
|
||||
{
|
||||
auto b = buffers->info[i];
|
||||
id<MTLBuffer> buffer = getMTLBuffer(b.buffer);
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
setBuffer(encoder, bindings, ShaderStage::STAGE_VERTEX, i + VERTEX_BUFFER_BINDING_START, buffer, b.offset);
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -920,7 +979,7 @@ void Graphics::draw(const DrawCommand &cmd)
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
setVertexBuffers(encoder, cmd.buffers);
|
||||
setVertexBuffers(encoder, cmd.buffers, renderBindings);
|
||||
|
||||
[encoder drawPrimitives:getMTLPrimitiveType(cmd.primitiveType)
|
||||
vertexStart:cmd.vertexStart
|
||||
@@ -937,7 +996,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
setVertexBuffers(encoder, cmd.buffers);
|
||||
setVertexBuffers(encoder, cmd.buffers, renderBindings);
|
||||
|
||||
auto indexType = cmd.indexType == INDEX_UINT32 ? MTLIndexTypeUInt32 : MTLIndexTypeUInt16;
|
||||
|
||||
@@ -961,7 +1020,7 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
setVertexBuffers(encoder, &buffers);
|
||||
setVertexBuffers(encoder, &buffers, renderBindings);
|
||||
|
||||
id<MTLBuffer> ib = getMTLBuffer(quadIndexBuffer);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user