mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Cache textures created by MakePixelsTexture and reuse where appropriate.
This commit is contained in:
1 parent
0b1abf1de9
commit
7c4b9bac90
10 files changed
+75
-27
No files matched your search
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user