Cache textures created by MakePixelsTexture and reuse where appropriate.

This commit is contained in:
Henrik Rydgård committed 2023-05-30 14:07:44 +02:00
1 parent 0b1abf1de9
commit 7c4b9bac90
10 files changed
+75 -27

No files matched your search

+3 -2
View File
@@ -92,7 +92,7 @@ public:
Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override;
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override;
@@ -796,6 +796,7 @@ public:
width_ = desc.width;
height_ = desc.height;
depth_ = desc.depth;
format_ = desc.format;
}
~D3D11Texture() {
if (tex)
@@ -944,7 +945,7 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
return tex;
}
void D3D11DrawContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) {
void D3D11DrawContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
D3D11Texture *tex = (D3D11Texture *)texture;
// TODO
}
+3 -4
View File
@@ -316,7 +316,6 @@ private:
LPDIRECT3DDEVICE9 device_;
LPDIRECT3DDEVICE9EX deviceEx_;
TextureType type_;
DataFormat format_;
D3DFORMAT d3dfmt_;
LPDIRECT3DTEXTURE9 tex_ = nullptr;
LPDIRECT3DVOLUMETEXTURE9 volTex_ = nullptr;
@@ -537,7 +536,7 @@ public:
Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override {
// Not implemented
@@ -940,9 +939,9 @@ Texture *D3D9Context::CreateTexture(const TextureDesc &desc) {
return tex;
}
void D3D9Context::UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) {
void D3D9Context::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
D3D9Texture *tex = (D3D9Texture *)texture;
tex->UpdateTextureLevels(data, numLevels, TextureCallback());
tex->UpdateTextureLevels(data, numLevels, initDataCallback);
}
+3 -4
View File
@@ -371,7 +371,7 @@ public:
void EndFrame() override;
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override;
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override;
@@ -862,7 +862,6 @@ private:
GLRenderManager *render_;
GLRTexture *tex_;
DataFormat format_;
TextureType type_;
int mipLevels_;
bool generateMips_; // Generate mips requested
@@ -1031,9 +1030,9 @@ Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) {
return new OpenGLTexture(&renderManager_, desc);
}
void OpenGLContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) {
void OpenGLContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
OpenGLTexture *tex = (OpenGLTexture *)texture;
tex->UpdateTextureLevels(&renderManager_, data, numLevels, TextureCallback());
tex->UpdateTextureLevels(&renderManager_, data, numLevels, initDataCallback);
}
DepthStencilState *OpenGLContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
+7 -7
View File
@@ -335,7 +335,9 @@ struct DescriptorSetKey {
class VKTexture : public Texture {
public:
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const TextureDesc &desc)
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {}
: vulkan_(vulkan), mipLevels_(desc.mipLevels) {
format_ = desc.format;
}
bool Create(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const TextureDesc &desc);
void Update(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const uint8_t *const *data, TextureCallback callback, int numLevels);
@@ -376,8 +378,6 @@ private:
VulkanTexture *vkTex_ = nullptr;
int mipLevels_ = 0;
DataFormat format_ = DataFormat::UNDEFINED;
};
class VKFramebuffer;
@@ -428,7 +428,7 @@ public:
Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override;
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override;
@@ -788,7 +788,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const Te
UpdateInternal(cmd, pushBuffer, desc.initData.data(), desc.initDataCallback, (int)desc.initData.size());
// Generate the rest of the mips automatically.
if (desc.initData.size() < mipLevels_) {
vkTex_->GenerateMips(cmd, desc.initData.size(), false);
vkTex_->GenerateMips(cmd, (int)desc.initData.size(), false);
layout = VK_IMAGE_LAYOUT_GENERAL;
}
}
@@ -1362,7 +1362,7 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) {
}
}
void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) {
void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
if (!push_ || !initCmd) {
// Too early! Fail.
@@ -1373,7 +1373,7 @@ void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, int
VKTexture *tex = (VKTexture *)texture;
_dbg_assert_(numLevels <= tex->NumLevels());
tex->Update(initCmd, push_, data, Draw::TextureCallback(), numLevels);
tex->Update(initCmd, push_, data, initDataCallback, numLevels);
}
static inline void CopySide(VkStencilOpState &dest, const StencilSetup &src) {
+2 -2
View File
@@ -132,6 +132,7 @@ bool RefCountedObject::Release() {
return true;
}
} else {
// No point in printing the name here if the object has already been free-d, it'll be corrupt and dangerous to print.
_dbg_assert_msg_(false, "Refcount (%d) invalid for object %p - corrupt?", refcount_.load(), this);
}
return false;
@@ -139,11 +140,10 @@ bool RefCountedObject::Release() {
bool RefCountedObject::ReleaseAssertLast() {
bool released = Release();
_dbg_assert_msg_(released, "RefCountedObject: Expected to be the last reference, but isn't!");
_dbg_assert_msg_(released, "RefCountedObject: Expected to be the last reference, but isn't! (%s)", name_);
return released;
}
// ================================== PIXEL/FRAGMENT SHADERS
// The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL.
+3 -1
View File
@@ -466,9 +466,11 @@ public:
int Width() { return width_; }
int Height() { return height_; }
int Depth() { return depth_; }
DataFormat Format() { return format_; }
protected:
int width_ = -1, height_ = -1, depth_ = -1;
DataFormat format_ = DataFormat::UNDEFINED;
};
struct BindingDesc {
@@ -734,7 +736,7 @@ public:
// Used to optimize DrawPixels by re-using previously allocated temp textures.
// Do not try to update a texture that might be used by an in-flight command buffer! In OpenGL and D3D, this will cause stalls
// while in Vulkan this might cause various strangeness like image corruption.
virtual void UpdateTextureLevels(Texture *texture, const uint8_t **data, int numLevels) = 0;
virtual void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) = 0;
virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) = 0;
virtual bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) = 0;
+42 -4
View File
@@ -1217,7 +1217,6 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
gpuStats.numUploads++;
pixelsTex->Release();
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);
@@ -1401,11 +1400,26 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
return true;
};
Draw::DataFormat texFormat = srcPixelFormat == GE_FORMAT_DEPTH16 ? depthFormat : preferredPixelsFormat_;
// Look for a matching texture we can re-use.
for (auto &iter : drawPixelsCache_) {
if (iter.frameNumber > gpuStats.numFlips - 3 || iter.tex->Width() != width || iter.tex->Height() != height || iter.tex->Format() != texFormat) {
continue;
}
// OK, current one seems good, let's use it (and mark it used).
gpuStats.numDrawPixels++;
draw_->UpdateTextureLevels(iter.tex, &srcPixels, generateTexture, 1);
iter.frameNumber = gpuStats.numFlips;
return iter.tex;
}
// Note: For depth, we create an R16_UNORM texture, that'll be just fine for uploading depth through a shader,
// and likely more efficient.
Draw::TextureDesc desc{
Draw::TextureType::LINEAR2D,
srcPixelFormat == GE_FORMAT_DEPTH16 ? depthFormat : preferredPixelsFormat_,
texFormat,
width,
height,
1,
@@ -1424,6 +1438,12 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
ERROR_LOG(G3D, "Failed to create DrawPixels texture");
}
gpuStats.numDrawPixels++;
gpuStats.numTexturesDecoded++; // Separate stat for this later?
INFO_LOG(G3D, "Creating drawPixelsCache texture: %dx%d", tex->Width(), tex->Height());
DrawPixelsEntry entry{ tex, gpuStats.numFlips };
drawPixelsCache_.push_back(entry);
return tex;
}
@@ -1450,7 +1470,6 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, int
presentation_->UpdateUniforms(textureCache_->VideoIsPlaying());
presentation_->SourceTexture(pixelsTex, 512, 272);
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1);
pixelsTex->Release();
// PresentationCommon sets all kinds of state, we can't rely on anything.
gstate_c.Dirty(DIRTY_ALL);
@@ -1672,6 +1691,20 @@ void FramebufferManagerCommon::DecimateFBOs() {
bvfbs_.erase(bvfbs_.begin() + i--);
}
}
// And DrawPixels cached textures.
for (auto it = drawPixelsCache_.begin(); it != drawPixelsCache_.end(); ) {
int age = gpuStats.numFlips - it->frameNumber;
if (age > 10) {
INFO_LOG(G3D, "Releasing drawPixelsCache texture: %dx%d", it->tex->Width(), it->tex->Height());
it->tex->Release();
it->tex = nullptr;
it = drawPixelsCache_.erase(it);
} else {
++it;
}
}
}
// Requires width/height to be set already.
@@ -2604,10 +2637,15 @@ void FramebufferManagerCommon::DestroyAllFBOs() {
}
tempFBOs_.clear();
for (auto iter : fbosToDelete_) {
for (auto &iter : fbosToDelete_) {
iter->Release();
}
fbosToDelete_.clear();
for (auto &iter : drawPixelsCache_) {
iter.tex->Release();
}
drawPixelsCache_.clear();
}
static const char *TempFBOReasonToString(TempFBO reason) {
+7
View File
@@ -267,6 +267,11 @@ namespace Draw {
class DrawContext;
}
struct DrawPixelsEntry {
Draw::Texture *tex;
int frameNumber;
};
struct GPUDebugBuffer;
class DrawEngineCommon;
class PresentationCommon;
@@ -571,6 +576,8 @@ protected:
std::vector<VirtualFramebuffer *> vfbs_;
std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
std::vector<DrawPixelsEntry> drawPixelsCache_;
bool gameUsesSequentialCopies_ = false;
// Sampled in BeginFrame/UpdateSize for safety.
+5 -2
View File
@@ -581,20 +581,23 @@ Draw::ShaderModule *PresentationCommon::CompileShaderModule(ShaderStage stage, S
}
void PresentationCommon::SourceTexture(Draw::Texture *texture, int bufferWidth, int bufferHeight) {
// AddRef before release and assign in case it's the same.
texture->AddRef();
DoRelease(srcTexture_);
DoRelease(srcFramebuffer_);
texture->AddRef();
srcTexture_ = texture;
srcWidth_ = bufferWidth;
srcHeight_ = bufferHeight;
}
void PresentationCommon::SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidth, int bufferHeight) {
fb->AddRef();
DoRelease(srcTexture_);
DoRelease(srcFramebuffer_);
fb->AddRef();
srcFramebuffer_ = fb;
srcWidth_ = bufferWidth;
srcHeight_ = bufferHeight;
-1
View File
@@ -354,7 +354,6 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size,
draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST, "WriteStencilFromMemory_Blit");
RebindFramebuffer("RebindFramebuffer - Stencil");
}
tex->Release();
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);