У меня есть приложение, которое выполняет некоторые вычисления на процессоре в нескольких потоках Каждый поток вычисляет область пикселей размером 64x64 для выходного изображения. Когда поток завершил свои вычисления, он загружает вычисленные данные пикселей в MTLTexture
через -[MTLTexture replaceRegion:]
. Перед запуском любого из потоков ЦП я поместил в текстуру версию полного результата в низком разрешении, и мне хотелось бы, чтобы потоки ЦП перезаписывали данные изображения при вычислении их с более высоким разрешением.
У меня это работает по большей части, но когда происходит первый вызов -replaceRegion:
, кажется, что текстура очищается до черного, а затем заменяет область 64x64 по запросу.
Вот как я создаю текстуру:
MTLTextureDescriptor* outputTextureDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:viewportSize.width
height:viewportSize.height
mipmapped:NO];
outputTextureDesc.usage = MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
_outputTexture = [device newTextureWithDescriptor:outputTextureDesc];
Затем, когда я хочу поместить в вывод текстуру в низком разрешении, я копирую ее из другой текстуры, подобной этой:
const Vertex2D quadVertices[] =
{
//Pixel Positions, Texture Coordinates
{ { viewportSize.x / 2.0, viewportSize.y / -2.0 }, { right, bottom } },
{ { viewportSize.x / -2.0, viewportSize.y / -2.0 }, { left, bottom } },
{ { viewportSize.x / -2.0, viewportSize.y / 2.0 }, { left, top } },
{ { viewportSize.x / 2.0, viewportSize.y / -2.0 }, { right, bottom } },
{ { viewportSize.x / -2.0, viewportSize.y / 2.0 }, { left, top } },
{ { viewportSize.x / 2.0, viewportSize.y / 2.0 }, { right, top } },
};
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDescriptor.colorAttachments [ 0 ].texture = _outputTexture;
renderPassDescriptor.colorAttachments [ 0 ].loadAction = MTLLoadActionDontCare;
renderPassDescriptor.colorAttachments [ 0 ].storeAction = MTLStoreActionStore;
if(renderPassDescriptor != nil)
{
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
commandBuffer.label = @"Copy Selection Command Buffer";
// Create a render command encoder so we can render into something
id<MTLRenderCommandEncoder> renderEncoder =
[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
renderEncoder.label = @"Copy Selection Command Encoder";
[renderEncoder setViewport:(MTLViewport){0.0, 0.0, viewportSize.x, viewportSize.y, -1.0, 1.0 }];
[renderEncoder setRenderPipelineState:renderPipelineState];
[renderEncoder setVertexBytes:quadVertices
length:sizeof(quadVertices)
atIndex:MBV_VertexIndex];
[renderEncoder setVertexBytes:&viewportSize
length:sizeof(viewportSize)
atIndex:MBV_ViewportSize];
[renderEncoder setFragmentTexture:oldRender
atIndex:MBF_Texture];
// Draw the vertices of our triangles
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:6];
[renderEncoder endEncoding];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
}
Я также попытался изменить renderPassDescriptor.colorAttachment [ 0 ].loadAction
на MTLLoadActionLoad
вместо MTLLoadActionDontCare
, как сказано в документации:
Существующее содержимое текстуры сохраняется.
но это не имело никакого значения.
Наконец, когда поток завершает работу, он загружает результат размером 64x64 пикселя, выполнив следующее:
MTLRegion currentRegion = { { colStart, rowStart, 0}, { colEnd - colStart, rowEnd - rowStart, 1 } };
[_outputTexture replaceRegion:currentRegion
mipmapLevel:0
withBytes:_outputBitmap + (rowStart * (int)viewportSize.width) + colStart
bytesPerRow:viewportSize.width * sizeof(*_outputBitmap)];
Если я использую инструменты отладки Metal, чтобы посмотреть на текстуру после начальной копии данных в низком разрешении, она содержит правильные пиксели. Но после первого звонка на -replaceRegion:
все, кроме региона, заменяется черным Последующие вызовы -replaceRegion:
работают правильно и не перезаписывают ранее записанные результаты.
Я должен отметить, что эта текстура также отображается, поскольку она обновляется MTKView
. Я иногда вижу копию в низком разрешении для кадра или двух до того, как плитки с высоким разрешением начинают заполняться. Любая идея, почему вызов -replaceRegion:
очистит текстуру? (Или что еще может очищать текстуру, если это не вызов -replaceRegion:
?)