mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
metal: improve texture initialization.
This commit is contained in:
@@ -78,6 +78,9 @@ Buffer::Buffer(love::graphics::Graphics *gfx, id<MTLDevice> device, const Settin
|
||||
// TODO: minimumTextureBufferAlignmentForPixelFormat
|
||||
|
||||
MTLPixelFormat pixformat = getMTLPixelFormat(getDataMember(0).decl.format);
|
||||
if (pixformat == MTLPixelFormatInvalid)
|
||||
throw love::Exception("Could not create Metal texel buffer: invalid format.");
|
||||
|
||||
size_t width = arraylength * getDataMembers().size();
|
||||
auto desc = [MTLTextureDescriptor textureBufferDescriptorWithPixelFormat:pixformat
|
||||
width:width
|
||||
|
||||
@@ -2062,6 +2062,11 @@ Graphics::RendererInfo Graphics::getRendererInfo() const
|
||||
|
||||
int Graphics::getClosestMSAASamples(int requestedsamples)
|
||||
{
|
||||
// We currently rely on StoreAndMultisampleResolve (unfortunately), which
|
||||
// isn't supported by old phone GPUs.
|
||||
if (!families.apple[3] && !families.mac[1] && !families.macCatalyst[1])
|
||||
return 1;
|
||||
|
||||
const int checkmsaa[] = {32, 16, 8, 4, 2};
|
||||
for (int samples : checkmsaa)
|
||||
{
|
||||
|
||||
@@ -105,43 +105,103 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id<MTLDevice> device, const
|
||||
|
||||
int mipcount = getMipmapCount();
|
||||
|
||||
int slicecount = 1;
|
||||
if (texType == TEXTURE_VOLUME)
|
||||
slicecount = getDepth();
|
||||
else if (texType == TEXTURE_2D_ARRAY)
|
||||
slicecount = getLayerCount();
|
||||
else if (texType == TEXTURE_CUBE)
|
||||
slicecount = 6;
|
||||
bool cangeneratemips = true;
|
||||
|
||||
if (isPixelFormatDepthStencil(format) || isPixelFormatCompressed(format))
|
||||
cangeneratemips = false;
|
||||
|
||||
// generateMipmapsForTexture is only supported for color renderable +
|
||||
// filterable formats.
|
||||
uint32 genmipsflags = PIXELFORMATUSAGEFLAGS_LINEAR | PIXELFORMATUSAGEFLAGS_RENDERTARGET;
|
||||
if (!gfx->isPixelFormatSupported(format, (PixelFormatUsageFlags) genmipsflags))
|
||||
cangeneratemips = false;
|
||||
|
||||
bool shouldgeneratemips = false;
|
||||
|
||||
std::vector<uint8> emptydata;
|
||||
MTLRenderPassDescriptor *passdesc = nil;
|
||||
|
||||
// Initialize texture.
|
||||
for (int mip = 0; mip < mipcount; mip++)
|
||||
{
|
||||
for (int slice = 0; slice < slicecount; slice++)
|
||||
for (int slice = 0; slice < getSliceCount(mip); slice++)
|
||||
{
|
||||
auto imgd = data != nullptr ? data->get(slice, mip) : nullptr;
|
||||
if (imgd != nullptr)
|
||||
{
|
||||
uploadImageData(imgd, mip, slice, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mip > 0 && cangeneratemips)
|
||||
{
|
||||
// Handled in the generateMipmaps call below.
|
||||
shouldgeneratemips = true;
|
||||
continue;
|
||||
}
|
||||
else if (getMSAA() <= 1 && !isPixelFormatDepthStencil(format) && !isPixelFormatCompressed(format))
|
||||
{
|
||||
// Initialize to transparent black.
|
||||
if (emptydata.empty())
|
||||
emptydata.resize(getPixelFormatSliceSize(format, w, h));
|
||||
|
||||
if (data == nullptr || data->get(0, 0) == nullptr)
|
||||
{
|
||||
// Initialize all slices to transparent black.
|
||||
if (!isPixelFormatDepthStencil(format))
|
||||
{
|
||||
std::vector<uint8> emptydata(getPixelFormatSliceSize(format, w, h));
|
||||
Rect r = {0, 0, w, h};
|
||||
for (int i = 0; i < slicecount; i++)
|
||||
uploadByteData(format, emptydata.data(), emptydata.size(), 0, i, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
Rect r = {0, 0, getPixelWidth(mip), getPixelHeight(mip)};
|
||||
uploadByteData(format, emptydata.data(), emptydata.size(), mip, slice, r);
|
||||
}
|
||||
else if (isRenderTarget())
|
||||
{
|
||||
// Clear to transparent black.
|
||||
gfx->submitAllEncoders(Graphics::SUBMIT_STORE);
|
||||
id<MTLCommandBuffer> cmd = gfx->useCommandBuffer();
|
||||
|
||||
if (passdesc == nil)
|
||||
passdesc = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
|
||||
auto configattachment = [&](MTLRenderPassAttachmentDescriptor *attachment)
|
||||
{
|
||||
attachment.texture = texture;
|
||||
attachment.level = mip;
|
||||
attachment.slice = texType == TEXTURE_VOLUME ? 0 : slice;
|
||||
attachment.depthPlane = texType == TEXTURE_VOLUME ? slice : 0;
|
||||
attachment.loadAction = MTLLoadActionClear;
|
||||
attachment.storeAction = MTLStoreActionStore;
|
||||
|
||||
if (actualMSAASamples > 1)
|
||||
{
|
||||
attachment.texture = msaaTexture;
|
||||
attachment.resolveTexture = texture;
|
||||
attachment.storeAction = MTLStoreActionStoreAndMultisampleResolve;
|
||||
}
|
||||
};
|
||||
|
||||
if (isPixelFormatDepth(format))
|
||||
{
|
||||
configattachment(passdesc.depthAttachment);
|
||||
passdesc.depthAttachment.clearDepth = 1.0;
|
||||
}
|
||||
if (isPixelFormatStencil(format))
|
||||
{
|
||||
configattachment(passdesc.stencilAttachment);
|
||||
passdesc.stencilAttachment.clearStencil = 0;
|
||||
}
|
||||
if (!isPixelFormatDepthStencil(format))
|
||||
{
|
||||
configattachment(passdesc.colorAttachments[0]);
|
||||
passdesc.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
id<MTLRenderCommandEncoder> encoder = [cmd renderCommandEncoderWithDescriptor:passdesc];
|
||||
[encoder endEncoding];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shouldn't be possible to get here.
|
||||
throw love::Exception("Could not initialize texture to transparent black.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Non-readable textures can't have mipmaps (enforced in the base class),
|
||||
// so generateMipmaps here is fine - when they aren't already initialized.
|
||||
if (getMipmapCount() > 1 && (data == nullptr || data->getMipmapCount() <= 1))
|
||||
if (shouldgeneratemips)
|
||||
generateMipmaps();
|
||||
|
||||
setSamplerState(samplerState);
|
||||
|
||||
Reference in New Issue
Block a user