188 lines
6.5 KiB
Plaintext
188 lines
6.5 KiB
Plaintext
//
|
|
// Copyright Contributors to the MaterialX Project
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include <MaterialXRenderMsl/MetalFramebuffer.h>
|
|
|
|
#include <MaterialXRenderMsl/MslPipelineStateObject.h>
|
|
#include <MaterialXRenderMsl/MslRenderer.h>
|
|
#include <MaterialXRenderMsl/MetalTextureHandler.h>
|
|
|
|
MATERIALX_NAMESPACE_BEGIN
|
|
|
|
//
|
|
// MetalFramebuffer methods
|
|
//
|
|
|
|
MetalFramebufferPtr MetalFramebuffer::create(id<MTLDevice> device,
|
|
unsigned int width, unsigned int height,
|
|
unsigned channelCount,
|
|
Image::BaseType baseType,
|
|
id<MTLTexture> colorTexture,
|
|
bool encodeSrgb,
|
|
MTLPixelFormat pixelFormat)
|
|
{
|
|
return MetalFramebufferPtr(new MetalFramebuffer(device,
|
|
width, height,
|
|
channelCount,
|
|
baseType,
|
|
colorTexture,
|
|
encodeSrgb,
|
|
pixelFormat));
|
|
}
|
|
|
|
MetalFramebuffer::MetalFramebuffer(id<MTLDevice> device,
|
|
unsigned int width, unsigned int height,
|
|
unsigned int channelCount,
|
|
Image::BaseType baseType,
|
|
id<MTLTexture> colorTexture,
|
|
bool encodeSrgb,
|
|
MTLPixelFormat pixelFormat) :
|
|
_width(0),
|
|
_height(0),
|
|
_channelCount(channelCount),
|
|
_baseType(baseType),
|
|
_encodeSrgb(encodeSrgb),
|
|
_device(device),
|
|
_colorTexture(colorTexture),
|
|
_depthTexture(0)
|
|
{
|
|
StringVec errors;
|
|
const string errorType("Metal target creation failure.");
|
|
|
|
resize(width, height, true, pixelFormat, colorTexture);
|
|
}
|
|
|
|
MetalFramebuffer::~MetalFramebuffer()
|
|
{
|
|
[_colorTexture release];
|
|
[_depthTexture release];
|
|
}
|
|
|
|
void MetalFramebuffer::resize(unsigned int width, unsigned int height, bool forceRecreate,
|
|
MTLPixelFormat pixelFormat,
|
|
id<MTLTexture> extColorTexture)
|
|
{
|
|
if (width * height <= 0)
|
|
{
|
|
return;
|
|
}
|
|
if (width != _width || _height != height || forceRecreate)
|
|
{
|
|
// Convert texture format to Metal
|
|
MTLDataType dataType;
|
|
if (pixelFormat == MTLPixelFormatInvalid)
|
|
MetalTextureHandler::mapTextureFormatToMetal(_baseType, _channelCount, _encodeSrgb, dataType, pixelFormat);
|
|
|
|
MTLTextureDescriptor* texDescriptor = [MTLTextureDescriptor
|
|
texture2DDescriptorWithPixelFormat:pixelFormat
|
|
width:width
|
|
height:height
|
|
mipmapped:NO];
|
|
[texDescriptor setStorageMode:MTLStorageModePrivate];
|
|
[texDescriptor setUsage:MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite];
|
|
|
|
if (extColorTexture == nil)
|
|
{
|
|
_colorTexture = [_device newTextureWithDescriptor:texDescriptor];
|
|
_colorTextureOwned = true;
|
|
}
|
|
else
|
|
{
|
|
_colorTexture = extColorTexture;
|
|
_colorTextureOwned = false;
|
|
}
|
|
|
|
texDescriptor.pixelFormat = MTLPixelFormatDepth32Float;
|
|
[texDescriptor setUsage:MTLTextureUsageRenderTarget];
|
|
_depthTexture = [_device newTextureWithDescriptor:texDescriptor];
|
|
|
|
_width = width;
|
|
_height = height;
|
|
}
|
|
}
|
|
|
|
void MetalFramebuffer::bind(MTLRenderPassDescriptor* renderpassDesc)
|
|
{
|
|
[renderpassDesc.colorAttachments[0] setTexture:getColorTexture()];
|
|
[renderpassDesc.colorAttachments[0] setLoadAction:MTLLoadActionClear];
|
|
[renderpassDesc.colorAttachments[0] setStoreAction:MTLStoreActionStore];
|
|
|
|
[renderpassDesc.depthAttachment setTexture:getDepthTexture()];
|
|
[renderpassDesc.depthAttachment setClearDepth:1.0];
|
|
[renderpassDesc.depthAttachment setLoadAction:MTLLoadActionClear];
|
|
[renderpassDesc.depthAttachment setStoreAction:MTLStoreActionStore];
|
|
[renderpassDesc setStencilAttachment:nil];
|
|
|
|
[renderpassDesc setRenderTargetWidth:_width];
|
|
[renderpassDesc setRenderTargetHeight:_height];
|
|
}
|
|
|
|
void MetalFramebuffer::unbind()
|
|
{
|
|
}
|
|
|
|
ImagePtr MetalFramebuffer::getColorImage(id<MTLCommandQueue> cmdQueue, ImagePtr image)
|
|
{
|
|
if (!image)
|
|
{
|
|
image = Image::create(_width, _height, _channelCount, _baseType);
|
|
image->createResourceBuffer();
|
|
}
|
|
|
|
if (cmdQueue == nil)
|
|
{
|
|
return image;
|
|
}
|
|
|
|
size_t bytesPerRow = _width * _channelCount * MetalTextureHandler::getTextureBaseTypeSize(_baseType);
|
|
size_t bytesPerImage = _height * bytesPerRow;
|
|
|
|
id<MTLBuffer> buffer = [_device newBufferWithLength:bytesPerImage options:MTLResourceStorageModeShared];
|
|
|
|
id<MTLCommandBuffer> cmdBuffer = [cmdQueue commandBuffer];
|
|
|
|
id<MTLBlitCommandEncoder> blitCmdEncoder = [cmdBuffer blitCommandEncoder];
|
|
[blitCmdEncoder copyFromTexture:_colorTexture
|
|
sourceSlice:0
|
|
sourceLevel:0
|
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
|
sourceSize:MTLSizeMake(_width, _height, 1)
|
|
toBuffer:buffer
|
|
destinationOffset:0
|
|
destinationBytesPerRow:bytesPerRow
|
|
destinationBytesPerImage:bytesPerImage
|
|
options:MTLBlitOptionNone];
|
|
|
|
[blitCmdEncoder endEncoding];
|
|
|
|
[cmdBuffer commit];
|
|
[cmdBuffer waitUntilCompleted];
|
|
|
|
std::vector<unsigned char> imageData(bytesPerImage);
|
|
memcpy(imageData.data(), [buffer contents], bytesPerImage);
|
|
|
|
if ([_colorTexture pixelFormat] == MTLPixelFormatBGRA8Unorm)
|
|
{
|
|
for (unsigned int j = 0; j < _height; ++j)
|
|
{
|
|
unsigned int rawStart = j * (_width * _channelCount);
|
|
for (unsigned int i = 0; i < _width; ++i)
|
|
{
|
|
unsigned int offset = rawStart + _channelCount * i;
|
|
unsigned char tmp = imageData[offset + 0];
|
|
imageData[offset + 0] = imageData[offset + 2];
|
|
imageData[offset + 2] = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
memcpy(image->getResourceBuffer(), imageData.data(), bytesPerImage);
|
|
[buffer release];
|
|
|
|
return image;
|
|
}
|
|
|
|
MATERIALX_NAMESPACE_END
|