mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Plug the texture memory leak
This commit is contained in:
parent
29341e53a5
commit
3bf88d7475
7 changed files with 88 additions and 63 deletions
|
@ -104,7 +104,7 @@ struct UB_VS_FS_Base {
|
|||
};
|
||||
|
||||
static const char *ub_baseStr =
|
||||
R"( mat4 proj_mtx;
|
||||
R"( mat4 proj_mtx;
|
||||
mat4 view_mtx;
|
||||
mat4 world_mtx;
|
||||
mat4 tex_mtx;
|
||||
|
@ -139,15 +139,15 @@ struct UB_VS_Lights {
|
|||
};
|
||||
|
||||
static const char *ub_vs_lightsStr =
|
||||
R"(vec4 globalAmbient;
|
||||
R"( vec4 globalAmbient;
|
||||
vec3 matdiffuse;
|
||||
vec4 matspecular;
|
||||
vec3 matemissive;
|
||||
vec3 pos[4];
|
||||
vec3 dir[4];
|
||||
vec3 att[4];
|
||||
vec4 matspecular;
|
||||
vec3 matemissive;
|
||||
vec3 pos[4];
|
||||
vec3 dir[4];
|
||||
vec3 att[4];
|
||||
float angle[4];
|
||||
float spotCoef[4];
|
||||
float spotCoef[4];
|
||||
vec3 ambient[4];
|
||||
vec3 diffuse[4];
|
||||
vec3 specular[4];
|
||||
|
@ -158,7 +158,7 @@ struct UB_VS_Bones {
|
|||
};
|
||||
|
||||
static const char *ub_vs_bonesStr =
|
||||
R"(mat4 m[8];
|
||||
R"( mat4 m[8];
|
||||
)";
|
||||
|
||||
class VulkanContext;
|
||||
|
|
|
@ -202,6 +202,7 @@ void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerV
|
|||
// Set cull
|
||||
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
key.cullMode = wantCull ? (gstate.getCullMode() ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT) : VK_CULL_MODE_NONE;
|
||||
key.cullMode = VK_CULL_MODE_NONE;
|
||||
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
|
@ -213,6 +214,8 @@ void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerV
|
|||
}
|
||||
} else {
|
||||
key.depthTestEnable = false;
|
||||
key.depthWriteEnable = false;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
|
|
|
@ -1446,9 +1446,10 @@ void TextureCacheVulkan::SetTexture() {
|
|||
}
|
||||
} else {
|
||||
entry->vkTex = new CachedTextureVulkan();
|
||||
entry->vkTex->texture_ = new VulkanTexture();
|
||||
entry->vkTex->texture_ = new VulkanTexture(vulkan_);
|
||||
VulkanTexture *image = entry->vkTex->texture_;
|
||||
image->Create(vulkan_, w, h, dstFmt);
|
||||
VkResult res = image->Create(w, h, dstFmt);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
lastBoundTexture = entry->vkTex;
|
||||
|
||||
|
@ -1786,11 +1787,11 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, int level, bool
|
|||
|
||||
// Upload the texture data. TODO: Decode directly into this buffer.
|
||||
int rowPitch;
|
||||
uint8_t *writePtr = entry.vkTex->texture_->Lock(vulkan_, level, &rowPitch);
|
||||
uint8_t *writePtr = entry.vkTex->texture_->Lock(level, &rowPitch);
|
||||
for (int y = 0; y < h; y++) {
|
||||
memcpy(writePtr + rowPitch * y, (const uint8_t *)pixelData + decPitch * y, rowBytes);
|
||||
}
|
||||
entry.vkTex->texture_->Unlock(vulkan_);
|
||||
entry.vkTex->texture_->Unlock();
|
||||
|
||||
/*
|
||||
if (!lowMemoryMode_) {
|
||||
|
|
|
@ -138,11 +138,11 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer) {
|
|||
// are present and what parts aren't, but we will not be ultra detailed about it.
|
||||
|
||||
WRITE(p, "\n");
|
||||
WRITE(p, "layout (std140, set = 0, binding = 2) uniform baseVars {\n%s\n} base;\n", ub_baseStr);
|
||||
WRITE(p, "layout (std140, set = 0, binding = 2) uniform baseVars {\n%s} base;\n", ub_baseStr);
|
||||
if (enableLighting || doShadeMapping)
|
||||
WRITE(p, "layout (std140, set = 0, binding = 3) uniform lightVars {\n%s\n} light;\n", ub_vs_lightsStr);
|
||||
WRITE(p, "layout (std140, set = 0, binding = 3) uniform lightVars {\n%s} light;\n", ub_vs_lightsStr);
|
||||
if (enableBones)
|
||||
WRITE(p, "layout (std140, set = 0, binding = 4) uniform boneVars {\n%s\n} bone;\n", ub_vs_bonesStr);
|
||||
WRITE(p, "layout (std140, set = 0, binding = 4) uniform boneVars {\n%s} bone;\n", ub_vs_bonesStr);
|
||||
|
||||
const char *shading = doFlatShading ? "flat " : "";
|
||||
|
||||
|
|
|
@ -1131,13 +1131,13 @@ void VulkanContext::InitCommandPool() {
|
|||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
VkResult VulkanTexture::Create(VulkanContext *vulkan, int w, int h, VkFormat format) {
|
||||
VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
|
||||
tex_width = w;
|
||||
tex_height = h;
|
||||
format_ = format;
|
||||
|
||||
VkFormatProperties formatProps;
|
||||
vkGetPhysicalDeviceFormatProperties(vulkan->GetPhysicalDevice(), format, &formatProps);
|
||||
vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
|
||||
|
||||
// See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
|
||||
// Linear tiling is usually only supported for 2D non-array textures.
|
||||
|
@ -1148,14 +1148,14 @@ VkResult VulkanTexture::Create(VulkanContext *vulkan, int w, int h, VkFormat for
|
|||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void VulkanTexture::CreateMappableImage(VulkanContext *vulkan) {
|
||||
void VulkanTexture::CreateMappableImage() {
|
||||
// If we already have a mappableImage, forget it.
|
||||
if (mappableImage) {
|
||||
vulkan->QueueDelete(mappableImage);
|
||||
vulkan_->QueueDelete(mappableImage);
|
||||
mappableImage = nullptr;
|
||||
}
|
||||
if (mappableMemory) {
|
||||
vulkan->QueueDelete(mappableMemory);
|
||||
vulkan_->QueueDelete(mappableMemory);
|
||||
mappableMemory = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1187,27 +1187,27 @@ void VulkanTexture::CreateMappableImage(VulkanContext *vulkan) {
|
|||
|
||||
// Create a mappable image. It will be the texture if linear images are ok to be textures
|
||||
// or it will be the staging image if they are not.
|
||||
VkResult res = vkCreateImage(vulkan->GetDevice(), &image_create_info, NULL, &mappableImage);
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &mappableImage);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan->GetDevice(), mappableImage, &mem_reqs);
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), mappableImage, &mem_reqs);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find the memory type that is host mappable.
|
||||
pass = vulkan->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
|
||||
pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan->GetDevice(), &mem_alloc, NULL, &(mappableMemory));
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &(mappableMemory));
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan->GetDevice(), mappableImage, mappableMemory, 0);
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), mappableImage, mappableMemory, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
uint8_t *VulkanTexture::Lock(VulkanContext *vulkan, int level, int *rowPitch) {
|
||||
CreateMappableImage(vulkan);
|
||||
uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
|
||||
CreateMappableImage();
|
||||
|
||||
VkImageSubresource subres = {};
|
||||
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
@ -1218,28 +1218,32 @@ uint8_t *VulkanTexture::Lock(VulkanContext *vulkan, int level, int *rowPitch) {
|
|||
void *data;
|
||||
|
||||
// Get the subresource layout so we know what the row pitch is
|
||||
vkGetImageSubresourceLayout(vulkan->GetDevice(), mappableImage, &subres, &layout);
|
||||
VkResult res = vkMapMemory(vulkan->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
|
||||
vkGetImageSubresourceLayout(vulkan_->GetDevice(), mappableImage, &subres, &layout);
|
||||
VkResult res = vkMapMemory(vulkan_->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
*rowPitch = (int)layout.rowPitch;
|
||||
return (uint8_t *)data;
|
||||
}
|
||||
|
||||
void VulkanTexture::Unlock(VulkanContext *vulkan) {
|
||||
vkUnmapMemory(vulkan->GetDevice(), mappableMemory);
|
||||
void VulkanTexture::Unlock() {
|
||||
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
|
||||
|
||||
VkCommandBuffer cmd = vulkan->GetInitCommandBuffer();
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
|
||||
// if we already have an image, queue it for destruction and forget it.
|
||||
if (image) {
|
||||
vulkan->QueueDelete(image);
|
||||
vulkan_->QueueDelete(image);
|
||||
image = nullptr;
|
||||
}
|
||||
if (view) {
|
||||
vulkan->QueueDelete(view);
|
||||
vulkan_->QueueDelete(view);
|
||||
view = nullptr;
|
||||
}
|
||||
if (mem) {
|
||||
vulkan_->QueueDelete(mem);
|
||||
mem = nullptr;
|
||||
}
|
||||
if (!needStaging) {
|
||||
/* If we can use the linear tiled image as a texture, just do it */
|
||||
image = mappableImage;
|
||||
|
@ -1267,10 +1271,10 @@ void VulkanTexture::Unlock(VulkanContext *vulkan) {
|
|||
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VkResult res = vkCreateImage(vulkan->GetDevice(), &image_create_info, NULL, &image);
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan->GetDevice(), image, &mem_reqs);
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc = {};
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
|
@ -1279,13 +1283,13 @@ void VulkanTexture::Unlock(VulkanContext *vulkan) {
|
|||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find memory type - don't specify any mapping requirements
|
||||
bool pass = vulkan->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
||||
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan->GetDevice(), &mem_alloc, NULL, &mem);
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan->GetDevice(), image, mem, 0);
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
|
||||
|
@ -1334,8 +1338,8 @@ void VulkanTexture::Unlock(VulkanContext *vulkan) {
|
|||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
imageLayout);
|
||||
|
||||
vulkan->QueueDelete(mappableMemory);
|
||||
vulkan->QueueDelete(mappableImage);
|
||||
vulkan_->QueueDelete(mappableMemory);
|
||||
vulkan_->QueueDelete(mappableImage);
|
||||
mappableImage = nullptr;
|
||||
mappableMemory = nullptr;
|
||||
}
|
||||
|
@ -1358,18 +1362,30 @@ void VulkanTexture::Unlock(VulkanContext *vulkan) {
|
|||
|
||||
/* create image view */
|
||||
view_info.image = image;
|
||||
VkResult res = vkCreateImageView(vulkan->GetDevice(), &view_info, NULL, &view);
|
||||
VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
void VulkanTexture::Destroy(VulkanContext *vulkan) {
|
||||
vulkan->QueueDelete(view);
|
||||
vulkan->QueueDelete(image);
|
||||
vulkan->QueueDelete(mem);
|
||||
void VulkanTexture::Destroy() {
|
||||
if (view) {
|
||||
vulkan_->QueueDelete(view);
|
||||
}
|
||||
if (image) {
|
||||
vulkan_->QueueDelete(image);
|
||||
if (mappableImage == image) {
|
||||
mappableImage = nullptr;
|
||||
}
|
||||
}
|
||||
if (mem) {
|
||||
vulkan_->QueueDelete(mem);
|
||||
if (mappableMemory == mem) {
|
||||
mappableMemory = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
view = NULL;
|
||||
image = NULL;
|
||||
mem = NULL;
|
||||
view = nullptr;
|
||||
image = nullptr;
|
||||
mem = nullptr;
|
||||
}
|
||||
|
||||
VkFence VulkanContext::CreateFence(bool presignalled) {
|
||||
|
|
|
@ -342,25 +342,30 @@ private:
|
|||
// Only supports simple 2D textures for now. Mipmap support will be added later.
|
||||
class VulkanTexture {
|
||||
public:
|
||||
VulkanTexture()
|
||||
: image(nullptr), imageLayout(VK_IMAGE_LAYOUT_UNDEFINED), mem(nullptr), view(nullptr), tex_width(0), tex_height(0), format_(VK_FORMAT_UNDEFINED),
|
||||
VulkanTexture(VulkanContext *vulkan)
|
||||
: vulkan_(vulkan), image(nullptr), imageLayout(VK_IMAGE_LAYOUT_UNDEFINED), mem(nullptr), view(nullptr), tex_width(0), tex_height(0), format_(VK_FORMAT_UNDEFINED),
|
||||
mappableImage(nullptr), mappableMemory(nullptr), needStaging(false) {
|
||||
}
|
||||
~VulkanTexture() {
|
||||
Destroy();
|
||||
}
|
||||
// Always call Create, Lock, Unlock. Unlock performs the upload if necessary.
|
||||
// Can later Lock and Unlock again. This cannot change the format. Create cannot
|
||||
// be called a second time without recreating the texture object.
|
||||
// be called a second time without recreating the texture object until Destroy has
|
||||
// been called.
|
||||
|
||||
VkResult Create(VulkanContext *vulkan, int w, int h, VkFormat format);
|
||||
uint8_t *Lock(VulkanContext *vulkan, int level, int *rowPitch);
|
||||
void Unlock(VulkanContext *vulkan);
|
||||
VkResult Create(int w, int h, VkFormat format);
|
||||
uint8_t *Lock(int level, int *rowPitch);
|
||||
void Unlock();
|
||||
|
||||
void Destroy(VulkanContext *vulkan);
|
||||
void Destroy();
|
||||
|
||||
VkImageView GetImageView() const { return view; }
|
||||
|
||||
private:
|
||||
void CreateMappableImage(VulkanContext *vulkan);
|
||||
void CreateMappableImage();
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
VkImage image;
|
||||
VkImageLayout imageLayout;
|
||||
VkDeviceMemory mem;
|
||||
|
|
|
@ -548,7 +548,7 @@ public:
|
|||
width_ = width;
|
||||
height_ = height;
|
||||
depth_ = depth;
|
||||
vkTex_ = new VulkanTexture();
|
||||
vkTex_ = new VulkanTexture(vulkan_);
|
||||
// We don't actually do anything here.
|
||||
return true;
|
||||
}
|
||||
|
@ -563,7 +563,7 @@ private:
|
|||
void Destroy() {
|
||||
ILOG("texture destroyed: %p", this);
|
||||
if (vkTex_) {
|
||||
vkTex_->Destroy(vulkan_);
|
||||
vkTex_->Destroy();
|
||||
delete vkTex_;
|
||||
}
|
||||
}
|
||||
|
@ -955,13 +955,13 @@ void Thin3DVKTexture::SetImageData(int x, int y, int z, int width, int height, i
|
|||
int bpp;
|
||||
VkFormat vulkanFormat = FormatToVulkan(format_, &bpp);
|
||||
int bytesPerPixel = bpp / 8;
|
||||
vkTex_->Create(vulkan_, width, height, vulkanFormat);
|
||||
vkTex_->Create(width, height, vulkanFormat);
|
||||
int rowPitch;
|
||||
uint8_t *dstData = vkTex_->Lock(vulkan_, 0, &rowPitch);
|
||||
uint8_t *dstData = vkTex_->Lock(0, &rowPitch);
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(dstData + rowPitch * y, data + stride * y, width * bytesPerPixel);
|
||||
}
|
||||
vkTex_->Unlock(vulkan_);
|
||||
vkTex_->Unlock();
|
||||
}
|
||||
|
||||
void Thin3DVKTexture::Finalize(int zim_flags) {
|
||||
|
|
Loading…
Add table
Reference in a new issue