I have this code to create an IOSurface from a bitmap image:
auto src = loadSource32f(); // rgba 32-bit float image
const auto desc = src->getDescriptor(); // metadata for that image
auto pixelFmt = CGMTLBufferManager::getCVPixelFormat( desc.channelBitDepth, desc.channelOrder ); // returns proper `RGfA`
int width = static_cast<int>( desc.width );
int height = static_cast<int>( desc.height );
int trowbytes = static_cast<int>( desc.trueRowbytes() ); // returns proper rowbytes value
CFMutableDictionaryRef properties = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue(
properties, kIOSurfaceWidth, CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &width ) );
CFDictionarySetValue(
properties, kIOSurfaceHeight, CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &height ) );
CFDictionarySetValue(
properties, kIOSurfacePixelFormat, CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &pixelFmt ) );
CFDictionarySetValue(
properties, kIOSurfaceBytesPerRow, CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &trowbytes ) );
NSDictionary *nsprops = ( __bridge NSDictionary * )properties;
IOSurface *oSurface = [[IOSurface alloc] initWithProperties:nsprops];
CFRelease( properties );
ASSERT_TRUE( oSurface );
auto ioSurface = (IOSurfaceRef) oSurface;
I tested that the pixels are properly written into the iosurface:
// copy data to surface
memcpy([oSurface baseAddress], src->getRawPtr(), src->getSizeInBytes());
auto surfPtr = (uint8_t*)[oSurface baseAddress];
// extract raw surface data and write it into a file
saveOutputRaw(desc, surfPtr, getFileName("IOSurfaceTestSurfaceRaw"));
And I see this:
Now I want to create a MTLTexture based on the iosurface:
// create texture
auto fmt = IOSurfaceGetPixelFormat( ioSurface );
auto w = IOSurfaceGetWidth( ioSurface );
auto h = IOSurfaceGetHeight( ioSurface );
auto rowbytes = IOSurfaceGetBytesPerRow( ioSurface );
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:CGMTLBufferManager::getMTLPixelFormat( fmt )
width:w
height:h
mipmapped:NO];
textureDescriptor.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
textureDescriptor.storageMode = MTLStorageModeShared;
auto device = MTLCreateSystemDefaultDevice();
id<MTLTexture> surfaceTex = [device newTextureWithDescriptor:textureDescriptor iosurface:ioSurface plane:0];
And now I want to test this:
auto region = MTLRegionMake2D(0, 0, w, h);
auto bufSize = [oSurface allocationSize];
// get texture bytes
auto outBuf2 = std::vector<uint8_t>(bufSize);
[surfaceTex getBytes:outBuf2.data()
bytesPerRow:rowbytes
fromRegion:region
mipmapLevel:0];
// save to file
saveOutputRaw(desc, outBuf2.data(), getFileName("IOSurfaceTestCreateTex"));
// get bytes
saveOutputRaw(desc, surfPtr, getFileName("IOSurfaceTestCreateRaw"));
And I get this result:
I also tried replaceRegion
and blitEncoder copyFromTexture: toTexture:
as well as managed texture with syncing, but the result is always the same - only the first 22 pixels get filled and the rest is transparent.
I have no idea what I'm missing. Please help.