mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +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
|
// TODO: minimumTextureBufferAlignmentForPixelFormat
|
||||||
|
|
||||||
MTLPixelFormat pixformat = getMTLPixelFormat(getDataMember(0).decl.format);
|
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();
|
size_t width = arraylength * getDataMembers().size();
|
||||||
auto desc = [MTLTextureDescriptor textureBufferDescriptorWithPixelFormat:pixformat
|
auto desc = [MTLTextureDescriptor textureBufferDescriptorWithPixelFormat:pixformat
|
||||||
width:width
|
width:width
|
||||||
|
|||||||
@@ -2062,6 +2062,11 @@ Graphics::RendererInfo Graphics::getRendererInfo() const
|
|||||||
|
|
||||||
int Graphics::getClosestMSAASamples(int requestedsamples)
|
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};
|
const int checkmsaa[] = {32, 16, 8, 4, 2};
|
||||||
for (int samples : checkmsaa)
|
for (int samples : checkmsaa)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,43 +105,103 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id<MTLDevice> device, const
|
|||||||
|
|
||||||
int mipcount = getMipmapCount();
|
int mipcount = getMipmapCount();
|
||||||
|
|
||||||
int slicecount = 1;
|
bool cangeneratemips = true;
|
||||||
if (texType == TEXTURE_VOLUME)
|
|
||||||
slicecount = getDepth();
|
|
||||||
else if (texType == TEXTURE_2D_ARRAY)
|
|
||||||
slicecount = getLayerCount();
|
|
||||||
else if (texType == TEXTURE_CUBE)
|
|
||||||
slicecount = 6;
|
|
||||||
|
|
||||||
|
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 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;
|
auto imgd = data != nullptr ? data->get(slice, mip) : nullptr;
|
||||||
if (imgd != nullptr)
|
if (imgd != nullptr)
|
||||||
|
{
|
||||||
uploadImageData(imgd, mip, slice, 0, 0);
|
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)
|
Rect r = {0, 0, getPixelWidth(mip), getPixelHeight(mip)};
|
||||||
{
|
uploadByteData(format, emptydata.data(), emptydata.size(), mip, slice, r);
|
||||||
// Initialize all slices to transparent black.
|
}
|
||||||
if (!isPixelFormatDepthStencil(format))
|
else if (isRenderTarget())
|
||||||
{
|
{
|
||||||
std::vector<uint8> emptydata(getPixelFormatSliceSize(format, w, h));
|
// Clear to transparent black.
|
||||||
Rect r = {0, 0, w, h};
|
gfx->submitAllEncoders(Graphics::SUBMIT_STORE);
|
||||||
for (int i = 0; i < slicecount; i++)
|
id<MTLCommandBuffer> cmd = gfx->useCommandBuffer();
|
||||||
uploadByteData(format, emptydata.data(), emptydata.size(), 0, i, r);
|
|
||||||
}
|
if (passdesc == nil)
|
||||||
else
|
passdesc = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
{
|
|
||||||
// TODO
|
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),
|
// Non-readable textures can't have mipmaps (enforced in the base class),
|
||||||
// so generateMipmaps here is fine - when they aren't already initialized.
|
// so generateMipmaps here is fine - when they aren't already initialized.
|
||||||
if (getMipmapCount() > 1 && (data == nullptr || data->getMipmapCount() <= 1))
|
if (shouldgeneratemips)
|
||||||
generateMipmaps();
|
generateMipmaps();
|
||||||
|
|
||||||
setSamplerState(samplerState);
|
setSamplerState(samplerState);
|
||||||
|
|||||||
Reference in New Issue
Block a user