generate mipmaps for custom textures when needed
This commit is contained in:
parent
015dcf117d
commit
03f096384b
|
@ -636,7 +636,7 @@ void BaseTextureCacheData::Update()
|
|||
need_32bit_buffer = false;
|
||||
// TODO avoid upscaling/depost. textures that change too often
|
||||
|
||||
bool mipmapped = IsMipmapped() && settings.rend.UseMipmaps && !settings.rend.DumpTextures;
|
||||
bool mipmapped = IsMipmapped() && !settings.rend.DumpTextures;
|
||||
|
||||
if (texconv32 != NULL && need_32bit_buffer)
|
||||
{
|
||||
|
@ -753,7 +753,7 @@ void BaseTextureCacheData::Update()
|
|||
//lock the texture to detect changes in it
|
||||
lock_block = libCore_vramlock_Lock(sa_tex,sa+size-1,this);
|
||||
|
||||
UploadToGPU(upscaled_w, upscaled_h, (u8*)temp_tex_buffer, mipmapped);
|
||||
UploadToGPU(upscaled_w, upscaled_h, (u8*)temp_tex_buffer, mipmapped, mipmapped);
|
||||
if (settings.rend.DumpTextures)
|
||||
{
|
||||
ComputeHash();
|
||||
|
@ -768,7 +768,7 @@ void BaseTextureCacheData::CheckCustomTexture()
|
|||
if (IsCustomTextureAvailable())
|
||||
{
|
||||
tex_type = TextureType::_8888;
|
||||
UploadToGPU(custom_width, custom_height, custom_image_data, false);
|
||||
UploadToGPU(custom_width, custom_height, custom_image_data, IsMipmapped(), false);
|
||||
delete [] custom_image_data;
|
||||
custom_image_data = NULL;
|
||||
}
|
||||
|
|
|
@ -689,7 +689,7 @@ struct BaseTextureCacheData
|
|||
|
||||
bool IsMipmapped()
|
||||
{
|
||||
return tcw.MipMapped != 0 && tcw.ScanOrder == 0;
|
||||
return tcw.MipMapped != 0 && tcw.ScanOrder == 0 && settings.rend.UseMipmaps;
|
||||
}
|
||||
|
||||
const char* GetPixelFormatName()
|
||||
|
@ -715,7 +715,7 @@ struct BaseTextureCacheData
|
|||
void Create();
|
||||
void ComputeHash();
|
||||
void Update();
|
||||
virtual void UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped) = 0;
|
||||
virtual void UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped, bool mipmapsIncluded = false) = 0;
|
||||
virtual bool Force32BitTexture(TextureType type) const { return false; }
|
||||
void CheckCustomTexture();
|
||||
//true if : dirty or paletted texture and hashes don't match
|
||||
|
|
|
@ -200,7 +200,7 @@ struct TextureCacheData : BaseTextureCacheData
|
|||
{
|
||||
GLuint texID; //gl texture
|
||||
virtual std::string GetId() override { return std::to_string(texID); }
|
||||
virtual void UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped) override;
|
||||
virtual void UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped, bool mipmapsIncluded = false) override;
|
||||
virtual bool Delete() override;
|
||||
};
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ static void dumpRtTexture(u32 name, u32 w, u32 h) {
|
|||
free(rows);
|
||||
}
|
||||
|
||||
void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped)
|
||||
void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped, bool mipmapsIncluded)
|
||||
{
|
||||
//upload to OpenGL !
|
||||
glcache.BindTexture(GL_TEXTURE_2D, texID);
|
||||
|
@ -94,7 +94,7 @@ void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, b
|
|||
die("Unsupported texture type");
|
||||
break;
|
||||
}
|
||||
if (mipmapped)
|
||||
if (mipmapsIncluded)
|
||||
{
|
||||
int mipmapLevels = 0;
|
||||
int dim = width;
|
||||
|
@ -149,9 +149,9 @@ void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, b
|
|||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,comps, width, height, 0, comps, gltype, temp_tex_buffer);
|
||||
if (mipmapped)
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
glCheck();
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk:
|
|||
commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, nullptr, nullptr, imageMemoryBarrier);
|
||||
}
|
||||
|
||||
void Texture::UploadToGPU(int width, int height, u8 *data, bool mipmapped)
|
||||
void Texture::UploadToGPU(int width, int height, u8 *data, bool mipmapped, bool mipmapsIncluded)
|
||||
{
|
||||
vk::Format format;
|
||||
u32 dataSize = width * height * 2;
|
||||
|
@ -167,7 +167,7 @@ void Texture::UploadToGPU(int width, int height, u8 *data, bool mipmapped)
|
|||
dataSize /= 2;
|
||||
break;
|
||||
}
|
||||
if (mipmapped)
|
||||
if (mipmapsIncluded)
|
||||
{
|
||||
int w = width / 2;
|
||||
u32 size = dataSize / 4;
|
||||
|
@ -180,13 +180,13 @@ void Texture::UploadToGPU(int width, int height, u8 *data, bool mipmapped)
|
|||
}
|
||||
bool isNew = true;
|
||||
if (width != extent.width || height != extent.height || format != this->format)
|
||||
Init(width, height, format, dataSize, mipmapped);
|
||||
Init(width, height, format, dataSize, mipmapped, mipmapsIncluded);
|
||||
else
|
||||
isNew = false;
|
||||
SetImage(dataSize, data, isNew);
|
||||
SetImage(dataSize, data, isNew, mipmapped && !mipmapsIncluded);
|
||||
}
|
||||
|
||||
void Texture::Init(u32 width, u32 height, vk::Format format, u32 dataSize, bool mipmapped)
|
||||
void Texture::Init(u32 width, u32 height, vk::Format format, u32 dataSize, bool mipmapped, bool mipmapsIncluded)
|
||||
{
|
||||
this->extent = vk::Extent2D(width, height);
|
||||
this->format = format;
|
||||
|
@ -217,6 +217,8 @@ void Texture::Init(u32 width, u32 height, vk::Format format, u32 dataSize, bool
|
|||
initialLayout = vk::ImageLayout::ePreinitialized;
|
||||
requirements = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible;
|
||||
}
|
||||
if (mipmapped && !mipmapsIncluded)
|
||||
usageFlags |= vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
CreateImage(imageTiling, usageFlags, initialLayout, requirements, vk::ImageAspectFlagBits::eColor);
|
||||
}
|
||||
|
||||
|
@ -238,7 +240,7 @@ void Texture::CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk:
|
|||
imageView = device.createImageViewUnique(imageViewCreateInfo);
|
||||
}
|
||||
|
||||
void Texture::SetImage(u32 srcSize, void *srcData, bool isNew)
|
||||
void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
|
||||
{
|
||||
verify((bool)commandBuffer);
|
||||
commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit));
|
||||
|
@ -261,7 +263,8 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew)
|
|||
// Since we're going to blit to the texture image, set its layout to eTransferDstOptimal
|
||||
setImageLayout(commandBuffer, image.get(), format, mipmapLevels, isNew ? vk::ImageLayout::eUndefined : vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
vk::ImageLayout::eTransferDstOptimal);
|
||||
if (mipmapLevels > 1)
|
||||
|
||||
if (mipmapLevels > 1 && !genMipmaps)
|
||||
{
|
||||
vk::DeviceSize bufferOffset = 0;
|
||||
for (int i = 0; i < mipmapLevels; i++)
|
||||
|
@ -277,18 +280,75 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew)
|
|||
vk::BufferImageCopy copyRegion(0, extent.width, extent.height, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
|
||||
vk::Offset3D(0, 0, 0), vk::Extent3D(extent, 1));
|
||||
commandBuffer.copyBufferToImage(stagingBufferData->buffer.get(), image.get(), vk::ImageLayout::eTransferDstOptimal, copyRegion);
|
||||
if (mipmapLevels > 1)
|
||||
GenerateMipmaps();
|
||||
}
|
||||
// Set the layout for the texture image from eTransferDstOptimal to SHADER_READ_ONLY
|
||||
setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can use the linear tiled image as a texture, just do it
|
||||
setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
if (mipmapLevels > 1)
|
||||
GenerateMipmaps();
|
||||
else
|
||||
// If we can use the linear tiled image as a texture, just do it
|
||||
setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
}
|
||||
commandBuffer.end();
|
||||
}
|
||||
|
||||
void Texture::GenerateMipmaps()
|
||||
{
|
||||
u32 mipWidth = extent.width;
|
||||
u32 mipHeight = extent.height;
|
||||
vk::ImageMemoryBarrier barrier(vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead,
|
||||
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
*image, vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
|
||||
|
||||
for (int i = 1; i < mipmapLevels; i++)
|
||||
{
|
||||
// Transition previous mipmap level from dst optimal/preinit to src optimal
|
||||
barrier.subresourceRange.baseMipLevel = i - 1;
|
||||
if (i == 1 && !needsStaging)
|
||||
{
|
||||
barrier.oldLayout = vk::ImageLayout::ePreinitialized;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eHostWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
}
|
||||
barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, barrier);
|
||||
|
||||
// Blit previous mipmap level on current
|
||||
vk::ImageBlit blit(vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, i - 1, 0, 1),
|
||||
{ { vk::Offset3D(0, 0, 0), vk::Offset3D(mipWidth, mipHeight, 1) } },
|
||||
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, i, 0, 1),
|
||||
{ { vk::Offset3D(0, 0, 0), vk::Offset3D(std::max(mipWidth / 2, 1u), std::max(mipHeight / 2, 1u), 1) } });
|
||||
commandBuffer.blitImage(*image, vk::ImageLayout::eTransferSrcOptimal, *image, vk::ImageLayout::eTransferDstOptimal, 1, &blit, vk::Filter::eLinear);
|
||||
|
||||
// Transition previous mipmap level from src optimal to shader read-only optimal
|
||||
barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr, barrier);
|
||||
|
||||
mipWidth = std::max(mipWidth / 2, 1u);
|
||||
mipHeight = std::max(mipHeight / 2, 1u);
|
||||
}
|
||||
// Transition last mipmap level from dst optimal to shader read-only optimal
|
||||
barrier.subresourceRange.baseMipLevel = mipmapLevels - 1;
|
||||
barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
|
||||
barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr, barrier);
|
||||
}
|
||||
|
||||
void FramebufferAttachment::Init(u32 width, u32 height, vk::Format format, vk::ImageUsageFlags usage)
|
||||
{
|
||||
this->format = format;
|
||||
|
|
|
@ -30,7 +30,7 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk:
|
|||
|
||||
struct Texture : BaseTextureCacheData
|
||||
{
|
||||
void UploadToGPU(int width, int height, u8 *data, bool mipmapped) override;
|
||||
void UploadToGPU(int width, int height, u8 *data, bool mipmapped, bool mipmapsIncluded = false) override;
|
||||
u64 GetIntId() { return (u64)reinterpret_cast<uintptr_t>(this); }
|
||||
std::string GetId() override { char s[20]; sprintf(s, "%p", this); return s; }
|
||||
bool IsNew() const { return !image.get(); }
|
||||
|
@ -43,10 +43,11 @@ struct Texture : BaseTextureCacheData
|
|||
void SetDevice(vk::Device device) { this->device = device; }
|
||||
|
||||
private:
|
||||
void Init(u32 width, u32 height, vk::Format format ,u32 dataSize, bool mipmapped);
|
||||
void SetImage(u32 size, void *data, bool isNew);
|
||||
void Init(u32 width, u32 height, vk::Format format ,u32 dataSize, bool mipmapped, bool mipmapsIncluded);
|
||||
void SetImage(u32 size, void *data, bool isNew, bool genMipmaps);
|
||||
void CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::ImageLayout initialLayout,
|
||||
vk::MemoryPropertyFlags memoryProperties, vk::ImageAspectFlags aspectMask);
|
||||
void GenerateMipmaps();
|
||||
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
vk::Extent2D extent;
|
||||
|
|
Loading…
Reference in New Issue