metal: Implement SDL_LockTexture for YUV formats.
authorAlex Szpakowski <slime73@gmail.com>
Wed, 19 Dec 2018 18:27:21 -0400
changeset 1248110fc11bbc967
parent 12480 bc0bc8a54387
child 12482 1acae5590352
metal: Implement SDL_LockTexture for YUV formats.
src/render/metal/SDL_render_metal.m
     1.1 --- a/src/render/metal/SDL_render_metal.m	Tue Dec 18 14:23:05 2018 -0400
     1.2 +++ b/src/render/metal/SDL_render_metal.m	Wed Dec 19 18:27:21 2018 -0400
     1.3 @@ -789,16 +789,22 @@
     1.4  { @autoreleasepool {
     1.5      METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
     1.6      METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
     1.7 +    int buffersize = 0;
     1.8  
     1.9 -    if (texturedata.yuv || texturedata.nv12) {
    1.10 -        /* FIXME: write me */
    1.11 -        return SDL_Unsupported();
    1.12 +    if (rect->w <= 0 || rect->h <= 0) {
    1.13 +        return SDL_SetError("Invalid rectangle dimensions for LockTexture.");
    1.14      }
    1.15  
    1.16      *pitch = SDL_BYTESPERPIXEL(texture->format) * rect->w;
    1.17  
    1.18 +    if (texturedata.yuv || texturedata.nv12) {
    1.19 +        buffersize = ((*pitch) * rect->h) + (2 * (*pitch + 1) / 2) * ((rect->h + 1) / 2);
    1.20 +    } else {
    1.21 +        buffersize = (*pitch) * rect->h;
    1.22 +    }
    1.23 +
    1.24      texturedata.lockedrect = *rect;
    1.25 -    texturedata.lockedbuffer = [data.mtldevice newBufferWithLength:(*pitch)*rect->h options:MTLResourceStorageModeShared];
    1.26 +    texturedata.lockedbuffer = [data.mtldevice newBufferWithLength:buffersize options:MTLResourceStorageModeShared];
    1.27      if (texturedata.lockedbuffer == nil) {
    1.28          return SDL_OutOfMemory();
    1.29      }
    1.30 @@ -814,6 +820,8 @@
    1.31      METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
    1.32      METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
    1.33      SDL_Rect rect = texturedata.lockedrect;
    1.34 +    int pitch = SDL_BYTESPERPIXEL(texture->format) * rect.w;
    1.35 +    SDL_Rect UVrect = {rect.x / 2, rect.y / 2, (rect.w + 1) / 2, (rect.h + 1) / 2};
    1.36  
    1.37      if (texturedata.lockedbuffer == nil) {
    1.38          return;
    1.39 @@ -832,7 +840,7 @@
    1.40  
    1.41      [blitcmd copyFromBuffer:texturedata.lockedbuffer
    1.42                 sourceOffset:0
    1.43 -          sourceBytesPerRow:SDL_BYTESPERPIXEL(texture->format) * rect.w
    1.44 +          sourceBytesPerRow:pitch
    1.45          sourceBytesPerImage:0
    1.46                   sourceSize:MTLSizeMake(rect.w, rect.h, 1)
    1.47                    toTexture:texturedata.mtltexture
    1.48 @@ -840,6 +848,46 @@
    1.49             destinationLevel:0
    1.50            destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
    1.51  
    1.52 +    if (texturedata.yuv) {
    1.53 +        int Uslice = texture->format == SDL_PIXELFORMAT_YV12 ? 1 : 0;
    1.54 +        int Vslice = texture->format == SDL_PIXELFORMAT_YV12 ? 0 : 1;
    1.55 +        int UVpitch = (pitch + 1) / 2;
    1.56 +
    1.57 +        [blitcmd copyFromBuffer:texturedata.lockedbuffer
    1.58 +                   sourceOffset:rect.h * pitch
    1.59 +              sourceBytesPerRow:UVpitch
    1.60 +            sourceBytesPerImage:UVpitch * UVrect.h
    1.61 +                     sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
    1.62 +                      toTexture:texturedata.mtltexture_uv
    1.63 +               destinationSlice:Uslice
    1.64 +               destinationLevel:0
    1.65 +              destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
    1.66 +
    1.67 +        [blitcmd copyFromBuffer:texturedata.lockedbuffer
    1.68 +                   sourceOffset:(rect.h * pitch) + UVrect.h * UVpitch
    1.69 +              sourceBytesPerRow:UVpitch
    1.70 +            sourceBytesPerImage:UVpitch * UVrect.h
    1.71 +                     sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
    1.72 +                      toTexture:texturedata.mtltexture_uv
    1.73 +               destinationSlice:Vslice
    1.74 +               destinationLevel:0
    1.75 +              destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
    1.76 +    }
    1.77 +
    1.78 +    if (texturedata.nv12) {
    1.79 +        int UVpitch = 2 * ((pitch + 1) / 2);
    1.80 +
    1.81 +        [blitcmd copyFromBuffer:texturedata.lockedbuffer
    1.82 +                   sourceOffset:rect.h * pitch
    1.83 +              sourceBytesPerRow:UVpitch
    1.84 +            sourceBytesPerImage:0
    1.85 +                     sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
    1.86 +                      toTexture:texturedata.mtltexture_uv
    1.87 +               destinationSlice:0
    1.88 +               destinationLevel:0
    1.89 +              destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
    1.90 +    }
    1.91 +
    1.92      [blitcmd endEncoding];
    1.93  
    1.94      [data.mtlcmdbuffer commit];