mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
metal: more robust render pass handling.
Initial implementation of captureScreenshot. Fix getStats().shaderswitches. Fix getStats().drawcalls.
This commit is contained in:
@@ -39,6 +39,12 @@ class Graphics final : public love::graphics::Graphics
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum SubmitType
|
||||||
|
{
|
||||||
|
SUBMIT_DONE,
|
||||||
|
SUBMIT_STORE,
|
||||||
|
};
|
||||||
|
|
||||||
struct RenderEncoderBindings
|
struct RenderEncoderBindings
|
||||||
{
|
{
|
||||||
void *textures[32][ShaderStage::STAGE_MAX_ENUM];
|
void *textures[32][ShaderStage::STAGE_MAX_ENUM];
|
||||||
@@ -107,15 +113,15 @@ public:
|
|||||||
bool usesGLSLES() const override;
|
bool usesGLSLES() const override;
|
||||||
RendererInfo getRendererInfo() const override;
|
RendererInfo getRendererInfo() const override;
|
||||||
|
|
||||||
void attachShader(love::graphics::Shader *shader);
|
void setShaderChanged();
|
||||||
|
|
||||||
id<MTLCommandBuffer> useCommandBuffer();
|
id<MTLCommandBuffer> useCommandBuffer();
|
||||||
id<MTLCommandBuffer> getCommandBuffer() const { return commandBuffer; }
|
id<MTLCommandBuffer> getCommandBuffer() const { return commandBuffer; }
|
||||||
void submitCommandBuffer();
|
void submitCommandBuffer(SubmitType type);
|
||||||
|
|
||||||
id<MTLRenderCommandEncoder> useRenderEncoder();
|
id<MTLRenderCommandEncoder> useRenderEncoder();
|
||||||
id<MTLRenderCommandEncoder> getRenderEncoder() const { return renderEncoder; }
|
id<MTLRenderCommandEncoder> getRenderEncoder() const { return renderEncoder; }
|
||||||
void submitRenderEncoder();
|
void submitRenderEncoder(SubmitType type);
|
||||||
|
|
||||||
id<MTLBlitCommandEncoder> useBlitEncoder();
|
id<MTLBlitCommandEncoder> useBlitEncoder();
|
||||||
id<MTLBlitCommandEncoder> getBlitEncoder() const { return blitEncoder; }
|
id<MTLBlitCommandEncoder> getBlitEncoder() const { return blitEncoder; }
|
||||||
@@ -206,6 +212,7 @@ private:
|
|||||||
uint32 dirtyRenderState;
|
uint32 dirtyRenderState;
|
||||||
VertexAttributes lastVertexAttributes;
|
VertexAttributes lastVertexAttributes;
|
||||||
bool windowHasStencil;
|
bool windowHasStencil;
|
||||||
|
int shaderSwitches;
|
||||||
|
|
||||||
StrongRef<love::graphics::Texture> backbufferMSAA;
|
StrongRef<love::graphics::Texture> backbufferMSAA;
|
||||||
StrongRef<love::graphics::Texture> backbufferDepthStencil;
|
StrongRef<love::graphics::Texture> backbufferDepthStencil;
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ Graphics::Graphics()
|
|||||||
, passDesc(nil)
|
, passDesc(nil)
|
||||||
, dirtyRenderState(STATEBIT_ALL)
|
, dirtyRenderState(STATEBIT_ALL)
|
||||||
, windowHasStencil(false)
|
, windowHasStencil(false)
|
||||||
|
, shaderSwitches(0)
|
||||||
, requestedBackbufferMSAA(0)
|
, requestedBackbufferMSAA(0)
|
||||||
, attachmentStoreActions()
|
, attachmentStoreActions()
|
||||||
, renderBindings()
|
, renderBindings()
|
||||||
@@ -331,7 +332,7 @@ Graphics::Graphics()
|
|||||||
|
|
||||||
Graphics::~Graphics()
|
Graphics::~Graphics()
|
||||||
{ @autoreleasepool {
|
{ @autoreleasepool {
|
||||||
submitCommandBuffer();
|
submitCommandBuffer(SUBMIT_DONE);
|
||||||
delete uniformBuffer;
|
delete uniformBuffer;
|
||||||
delete defaultAttributesBuffer;
|
delete defaultAttributesBuffer;
|
||||||
passDesc = nil;
|
passDesc = nil;
|
||||||
@@ -441,7 +442,7 @@ void Graphics::unSetMode()
|
|||||||
|
|
||||||
flushBatchedDraws();
|
flushBatchedDraws();
|
||||||
|
|
||||||
submitCommandBuffer();
|
submitCommandBuffer(SUBMIT_DONE);
|
||||||
|
|
||||||
for (auto temp : temporaryTextures)
|
for (auto temp : temporaryTextures)
|
||||||
temp.texture->release();
|
temp.texture->release();
|
||||||
@@ -459,9 +460,10 @@ void Graphics::setActive(bool enable)
|
|||||||
active = enable;
|
active = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::attachShader(love::graphics::Shader *shader)
|
void Graphics::setShaderChanged()
|
||||||
{
|
{
|
||||||
dirtyRenderState |= STATE_SHADER;
|
dirtyRenderState |= STATE_SHADER;
|
||||||
|
++shaderSwitches;
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLCommandBuffer> Graphics::useCommandBuffer()
|
id<MTLCommandBuffer> Graphics::useCommandBuffer()
|
||||||
@@ -481,9 +483,9 @@ id<MTLCommandBuffer> Graphics::useCommandBuffer()
|
|||||||
return commandBuffer;
|
return commandBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::submitCommandBuffer()
|
void Graphics::submitCommandBuffer(SubmitType type)
|
||||||
{
|
{
|
||||||
submitRenderEncoder();
|
submitRenderEncoder(type);
|
||||||
submitBlitEncoder();
|
submitBlitEncoder();
|
||||||
|
|
||||||
if (commandBuffer != nil)
|
if (commandBuffer != nil)
|
||||||
@@ -570,17 +572,6 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
|
|||||||
|
|
||||||
renderBindings = {};
|
renderBindings = {};
|
||||||
|
|
||||||
for (int i = 0; i < MAX_COLOR_RENDER_TARGETS; i++)
|
|
||||||
{
|
|
||||||
passDesc.colorAttachments[0].texture = nil;
|
|
||||||
passDesc.colorAttachments[0].resolveTexture = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
passDesc.depthAttachment.texture = nil;
|
|
||||||
passDesc.depthAttachment.resolveTexture = nil;
|
|
||||||
passDesc.stencilAttachment.texture = nil;
|
|
||||||
passDesc.stencilAttachment.resolveTexture = nil;
|
|
||||||
|
|
||||||
id<MTLBuffer> defaultbuffer = getMTLBuffer(defaultAttributesBuffer);
|
id<MTLBuffer> defaultbuffer = getMTLBuffer(defaultAttributesBuffer);
|
||||||
setBuffer(renderEncoder, renderBindings, ShaderStage::STAGE_VERTEX, DEFAULT_VERTEX_BUFFER_BINDING, defaultbuffer, 0);
|
setBuffer(renderEncoder, renderBindings, ShaderStage::STAGE_VERTEX, DEFAULT_VERTEX_BUFFER_BINDING, defaultbuffer, 0);
|
||||||
|
|
||||||
@@ -590,28 +581,45 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
|
|||||||
return renderEncoder;
|
return renderEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::submitRenderEncoder()
|
void Graphics::submitRenderEncoder(SubmitType type)
|
||||||
{
|
{
|
||||||
if (renderEncoder != nil)
|
if (renderEncoder != nil)
|
||||||
{
|
{
|
||||||
|
bool store = type == SUBMIT_STORE;
|
||||||
const auto &actions = attachmentStoreActions;
|
const auto &actions = attachmentStoreActions;
|
||||||
const auto &rts = states.back().renderTargets;
|
const auto &rts = states.back().renderTargets;
|
||||||
bool isbackbuffer = rts.getFirstTarget().texture.get() == nullptr;
|
bool isbackbuffer = rts.getFirstTarget().texture.get() == nullptr;
|
||||||
|
|
||||||
if (isbackbuffer)
|
if (isbackbuffer)
|
||||||
[renderEncoder setColorStoreAction:actions.color[0] atIndex:0];
|
[renderEncoder setColorStoreAction:(store ? MTLStoreActionStore : actions.color[0]) atIndex:0];
|
||||||
|
|
||||||
for (size_t i = 0; i < rts.colors.size(); i++)
|
for (size_t i = 0; i < rts.colors.size(); i++)
|
||||||
[renderEncoder setColorStoreAction:actions.color[i] atIndex:i];
|
[renderEncoder setColorStoreAction:(store ? MTLStoreActionStore : actions.color[i]) atIndex:i];
|
||||||
|
|
||||||
if (rts.depthStencil.texture.get() || rts.temporaryRTFlags != 0 || isbackbuffer)
|
if (rts.depthStencil.texture.get() || rts.temporaryRTFlags != 0 || isbackbuffer)
|
||||||
{
|
{
|
||||||
[renderEncoder setDepthStoreAction:actions.depth];
|
[renderEncoder setDepthStoreAction:store ? MTLStoreActionStore : actions.depth];
|
||||||
[renderEncoder setStencilStoreAction:actions.stencil];
|
[renderEncoder setStencilStoreAction:store ? MTLStoreActionStore : actions.stencil];
|
||||||
}
|
}
|
||||||
|
|
||||||
[renderEncoder endEncoding];
|
[renderEncoder endEncoding];
|
||||||
renderEncoder = nil;
|
renderEncoder = nil;
|
||||||
|
|
||||||
|
// Reset actions to load. The next clear/discard/etc will set more
|
||||||
|
// appropriate actions if necessary.
|
||||||
|
for (int i = 0; i < MAX_COLOR_RENDER_TARGETS; i++)
|
||||||
|
{
|
||||||
|
passDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
|
||||||
|
passDesc.colorAttachments[i].texture = nil;
|
||||||
|
passDesc.colorAttachments[i].resolveTexture = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
passDesc.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||||
|
passDesc.depthAttachment.texture = nil;
|
||||||
|
passDesc.depthAttachment.resolveTexture = nil;
|
||||||
|
passDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
|
||||||
|
passDesc.stencilAttachment.texture = nil;
|
||||||
|
passDesc.stencilAttachment.resolveTexture = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +627,7 @@ id<MTLBlitCommandEncoder> Graphics::useBlitEncoder()
|
|||||||
{
|
{
|
||||||
if (blitEncoder == nil)
|
if (blitEncoder == nil)
|
||||||
{
|
{
|
||||||
submitRenderEncoder();
|
submitRenderEncoder(SUBMIT_STORE);
|
||||||
blitEncoder = [useCommandBuffer() blitCommandEncoder];
|
blitEncoder = [useCommandBuffer() blitCommandEncoder];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -985,6 +993,8 @@ void Graphics::draw(const DrawCommand &cmd)
|
|||||||
vertexStart:cmd.vertexStart
|
vertexStart:cmd.vertexStart
|
||||||
vertexCount:cmd.vertexCount
|
vertexCount:cmd.vertexCount
|
||||||
instanceCount:cmd.instanceCount];
|
instanceCount:cmd.instanceCount];
|
||||||
|
|
||||||
|
++drawCalls;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
void Graphics::draw(const DrawIndexedCommand &cmd)
|
void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||||
@@ -1006,6 +1016,8 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
|||||||
indexBuffer:getMTLBuffer(cmd.indexBuffer)
|
indexBuffer:getMTLBuffer(cmd.indexBuffer)
|
||||||
indexBufferOffset:cmd.indexBufferOffset
|
indexBufferOffset:cmd.indexBufferOffset
|
||||||
instanceCount:cmd.instanceCount];
|
instanceCount:cmd.instanceCount];
|
||||||
|
|
||||||
|
++drawCalls;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
void Graphics::drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture)
|
void Graphics::drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture)
|
||||||
@@ -1099,13 +1111,14 @@ void Graphics::endPass()
|
|||||||
auto &rts = states.back().renderTargets;
|
auto &rts = states.back().renderTargets;
|
||||||
love::graphics::Texture *depthstencil = rts.depthStencil.texture.get();
|
love::graphics::Texture *depthstencil = rts.depthStencil.texture.get();
|
||||||
|
|
||||||
// Discard the depth/stencil buffer if we're using an internal cached one.
|
// Discard the depth/stencil buffer if we're using an internal cached one,
|
||||||
|
// or if this is the backbuffer.
|
||||||
if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
|
if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
|
||||||
discard({}, true);
|
discard({}, true);
|
||||||
else if (!rts.getFirstTarget().texture.get())
|
else if (!rts.getFirstTarget().texture.get())
|
||||||
discard({}, true); // Backbuffer
|
discard({}, true); // Backbuffer
|
||||||
|
|
||||||
submitRenderEncoder();
|
submitRenderEncoder(SUBMIT_DONE);
|
||||||
|
|
||||||
for (const auto &rt : rts.colors)
|
for (const auto &rt : rts.colors)
|
||||||
{
|
{
|
||||||
@@ -1117,9 +1130,17 @@ void Graphics::endPass()
|
|||||||
void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
|
void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
|
||||||
{ @autoreleasepool {
|
{ @autoreleasepool {
|
||||||
if (c.hasValue || stencil.hasValue || depth.hasValue)
|
if (c.hasValue || stencil.hasValue || depth.hasValue)
|
||||||
|
{
|
||||||
flushBatchedDraws();
|
flushBatchedDraws();
|
||||||
|
|
||||||
// TODO: handle clearing mid-pass
|
// Handle clearing mid-pass by starting a new pass.
|
||||||
|
if (renderEncoder != nil)
|
||||||
|
{
|
||||||
|
submitRenderEncoder(SUBMIT_STORE);
|
||||||
|
useRenderEncoder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c.hasValue)
|
if (c.hasValue)
|
||||||
{
|
{
|
||||||
gammaCorrectColor(c.value);
|
gammaCorrectColor(c.value);
|
||||||
@@ -1160,7 +1181,13 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
|
|||||||
|
|
||||||
flushBatchedDraws();
|
flushBatchedDraws();
|
||||||
|
|
||||||
// TODO: handle clearing mid-pass
|
// Handle clearing mid-pass by starting a new pass.
|
||||||
|
if (renderEncoder != nil)
|
||||||
|
{
|
||||||
|
submitRenderEncoder(SUBMIT_STORE);
|
||||||
|
useRenderEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ncolors; i++)
|
for (int i = 0; i < ncolors; i++)
|
||||||
{
|
{
|
||||||
if (!colors[i].hasValue)
|
if (!colors[i].hasValue)
|
||||||
@@ -1204,62 +1231,31 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
|
|
||||||
endPass();
|
endPass();
|
||||||
|
|
||||||
|
id<MTLBuffer> screenshotbuffer = nil;
|
||||||
|
|
||||||
if (!pendingScreenshotCallbacks.empty())
|
if (!pendingScreenshotCallbacks.empty())
|
||||||
{
|
{
|
||||||
int w = getPixelWidth();
|
int w = activeDrawable.texture.width;
|
||||||
int h = getPixelHeight();
|
int h = activeDrawable.texture.height;
|
||||||
|
size_t size = w * h * 4;
|
||||||
|
|
||||||
size_t row = 4 * w;
|
screenshotbuffer = [device newBufferWithLength:size options:MTLResourceStorageModeShared];
|
||||||
size_t size = row * h;
|
if (screenshotbuffer == nil)
|
||||||
|
throw love::Exception("Out of graphics memory.");
|
||||||
|
|
||||||
uint8 *screenshot = nullptr;
|
auto blitencoder = useBlitEncoder();
|
||||||
|
|
||||||
try
|
[blitencoder copyFromTexture:activeDrawable.texture
|
||||||
{
|
sourceSlice:0
|
||||||
screenshot = new uint8[size];
|
sourceLevel:0
|
||||||
}
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
catch (std::exception &)
|
sourceSize:MTLSizeMake(w, h, 0)
|
||||||
{
|
toBuffer:screenshotbuffer
|
||||||
delete[] screenshot;
|
destinationOffset:0
|
||||||
throw love::Exception("Out of memory.");
|
destinationBytesPerRow:w * 4
|
||||||
}
|
destinationBytesPerImage:size];
|
||||||
|
|
||||||
// TODO
|
submitBlitEncoder();
|
||||||
|
|
||||||
// Replace alpha values with full opacity.
|
|
||||||
for (size_t i = 3; i < size; i += 4)
|
|
||||||
screenshot[i] = 255;
|
|
||||||
|
|
||||||
auto imagemodule = Module::getInstance<love::image::Image>(M_IMAGE);
|
|
||||||
|
|
||||||
for (int i = 0; i < (int) pendingScreenshotCallbacks.size(); i++)
|
|
||||||
{
|
|
||||||
const auto &info = pendingScreenshotCallbacks[i];
|
|
||||||
image::ImageData *img = nullptr;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
img = imagemodule->newImageData(w, h, PIXELFORMAT_RGBA8_UNORM, screenshot);
|
|
||||||
}
|
|
||||||
catch (love::Exception &)
|
|
||||||
{
|
|
||||||
delete[] screenshot;
|
|
||||||
info.callback(&info, nullptr, nullptr);
|
|
||||||
for (int j = i + 1; j < (int) pendingScreenshotCallbacks.size(); j++)
|
|
||||||
{
|
|
||||||
const auto &ninfo = pendingScreenshotCallbacks[j];
|
|
||||||
ninfo.callback(&ninfo, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
pendingScreenshotCallbacks.clear();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.callback(&info, img, screenshotCallbackData);
|
|
||||||
img->release();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] screenshot;
|
|
||||||
pendingScreenshotCallbacks.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (StreamBuffer *buffer : batchedDrawState.vb)
|
for (StreamBuffer *buffer : batchedDrawState.vb)
|
||||||
@@ -1275,7 +1271,56 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
if (cmd != nil && activeDrawable != nil)
|
if (cmd != nil && activeDrawable != nil)
|
||||||
[cmd presentDrawable:activeDrawable];
|
[cmd presentDrawable:activeDrawable];
|
||||||
|
|
||||||
submitCommandBuffer();
|
submitCommandBuffer(SUBMIT_DONE);
|
||||||
|
|
||||||
|
if (!pendingScreenshotCallbacks.empty())
|
||||||
|
{
|
||||||
|
[cmd waitUntilCompleted];
|
||||||
|
|
||||||
|
int w = activeDrawable.texture.width;
|
||||||
|
int h = activeDrawable.texture.height;
|
||||||
|
size_t size = w * h * 4;
|
||||||
|
|
||||||
|
auto imagemodule = Module::getInstance<love::image::Image>(M_IMAGE);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int) pendingScreenshotCallbacks.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &info = pendingScreenshotCallbacks[i];
|
||||||
|
image::ImageData *img = nullptr;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
img = imagemodule->newImageData(w, h, PIXELFORMAT_RGBA8_UNORM, screenshotbuffer.contents);
|
||||||
|
}
|
||||||
|
catch (love::Exception &)
|
||||||
|
{
|
||||||
|
info.callback(&info, nullptr, nullptr);
|
||||||
|
for (int j = i + 1; j < (int) pendingScreenshotCallbacks.size(); j++)
|
||||||
|
{
|
||||||
|
const auto &ninfo = pendingScreenshotCallbacks[j];
|
||||||
|
ninfo.callback(&ninfo, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
pendingScreenshotCallbacks.clear();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 *screenshot = (uint8 *) img->getData();
|
||||||
|
|
||||||
|
// Convert from BGRA to RGBA and replace alpha with full opacity.
|
||||||
|
for (size_t i = 0; i < size; i += 4)
|
||||||
|
{
|
||||||
|
uint8 r = screenshot[i + 2];
|
||||||
|
screenshot[i + 2] = screenshot[i + 0];
|
||||||
|
screenshot[i + 0] = r;
|
||||||
|
screenshot[i + 3] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.callback(&info, img, screenshotCallbackData);
|
||||||
|
img->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingScreenshotCallbacks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
auto window = Module::getInstance<love::window::Window>(M_WINDOW);
|
auto window = Module::getInstance<love::window::Window>(M_WINDOW);
|
||||||
if (window != nullptr)
|
if (window != nullptr)
|
||||||
@@ -1288,7 +1333,7 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
|
|
||||||
// Reset the per-frame stat counts.
|
// Reset the per-frame stat counts.
|
||||||
drawCalls = 0;
|
drawCalls = 0;
|
||||||
//gl.stats.shaderSwitches = 0;
|
shaderSwitches = 0;
|
||||||
renderTargetSwitchCount = 0;
|
renderTargetSwitchCount = 0;
|
||||||
drawCallsBatched = 0;
|
drawCallsBatched = 0;
|
||||||
|
|
||||||
@@ -1806,8 +1851,7 @@ void Graphics::initCapabilities()
|
|||||||
|
|
||||||
void Graphics::getAPIStats(int &shaderswitches) const
|
void Graphics::getAPIStats(int &shaderswitches) const
|
||||||
{
|
{
|
||||||
// TODO
|
shaderswitches = shaderSwitches;
|
||||||
shaderswitches = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // metal
|
} // metal
|
||||||
|
|||||||
@@ -737,7 +737,7 @@ void Shader::attach()
|
|||||||
{
|
{
|
||||||
Graphics *gfx = Graphics::getInstance();
|
Graphics *gfx = Graphics::getInstance();
|
||||||
gfx->flushBatchedDraws();
|
gfx->flushBatchedDraws();
|
||||||
gfx->attachShader(this);
|
gfx->setShaderChanged();
|
||||||
current = this;
|
current = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ void Texture::readbackImageData(love::image::ImageData *imagedata, int slice, in
|
|||||||
id<MTLCommandBuffer> cmd = gfx->getCommandBuffer();
|
id<MTLCommandBuffer> cmd = gfx->getCommandBuffer();
|
||||||
|
|
||||||
gfx->submitBlitEncoder();
|
gfx->submitBlitEncoder();
|
||||||
gfx->submitCommandBuffer();
|
gfx->submitCommandBuffer(Graphics::SUBMIT_STORE);
|
||||||
|
|
||||||
[cmd waitUntilCompleted];
|
[cmd waitUntilCompleted];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user