metal: Fix SDL_RenderReadPixels to wait for the GPU to finish rendering to the active texture before reading its pixels.
authorAlex Szpakowski <slime73@gmail.com>
Sat, 13 Oct 2018 03:36:42 -0300
changeset 12322b5074e5aaa49
parent 12321 4216eccf4ea2
child 12323 43cae18a1a34
metal: Fix SDL_RenderReadPixels to wait for the GPU to finish rendering to the active texture before reading its pixels.
src/render/metal/SDL_render_metal.m
     1.1 --- a/src/render/metal/SDL_render_metal.m	Fri Oct 12 23:23:52 2018 -0300
     1.2 +++ b/src/render/metal/SDL_render_metal.m	Sat Oct 13 03:36:42 2018 -0300
     1.3 @@ -1351,10 +1351,23 @@
     1.4  METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
     1.5                      Uint32 pixel_format, void * pixels, int pitch)
     1.6  { @autoreleasepool {
     1.7 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
     1.8 +
     1.9 +    /* Make sure we have a valid MTLTexture to read from, and an active command
    1.10 +     * buffer we can wait for. */
    1.11      METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
    1.12  
    1.13 -    // !!! FIXME: this probably needs to commit the current command buffer, and probably waitUntilCompleted
    1.14 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
    1.15 +    /* Wait for the current command buffer to finish, so we don't read from the
    1.16 +     * texture before the GPU finishes rendering to it. */
    1.17 +    if (data.mtlcmdencoder) {
    1.18 +        [data.mtlcmdencoder endEncoding];
    1.19 +        [data.mtlcmdbuffer commit];
    1.20 +        [data.mtlcmdbuffer waitUntilCompleted];
    1.21 +
    1.22 +        data.mtlcmdencoder = nil;
    1.23 +        data.mtlcmdbuffer = nil;
    1.24 +    }
    1.25 +
    1.26      id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
    1.27      MTLRegion mtlregion = MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h);
    1.28  
    1.29 @@ -1370,6 +1383,13 @@
    1.30      const Uint32 temp_format = (mtltexture.pixelFormat == MTLPixelFormatBGRA8Unorm) ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_ABGR8888;
    1.31      const int status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
    1.32      SDL_free(temp_pixels);
    1.33 +
    1.34 +    /* Set up an active command buffer and encoder once we're done. It will use
    1.35 +     * the same texture that was active before (even if it's part of the swap
    1.36 +     * chain), since we didn't clear that when waiting for the command buffer to
    1.37 +     * complete. */
    1.38 +    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
    1.39 +
    1.40      return status;
    1.41  }}
    1.42