mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-11 09:05:38 +00:00
Cache and hash data for DrawPixels.
We already had a cache to reuse texture objects so just opportunistically reuse them when easy to do so.
This commit is contained in:
parent
3287c268ff
commit
632fa1c9d6
@ -1208,7 +1208,6 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
|
|||||||
vfb ? vfb->bufferHeight : g_display.pixel_yres,
|
vfb ? vfb->bufferHeight : g_display.pixel_yres,
|
||||||
u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||||
|
|
||||||
gpuStats.numUploads++;
|
|
||||||
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
|
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
|
||||||
|
|
||||||
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);
|
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);
|
||||||
@ -1324,6 +1323,19 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bpp = BufferFormatBytesPerPixel(srcPixelFormat);
|
||||||
|
int srcStrideInBytes = srcStride * bpp;
|
||||||
|
int widthInBytes = width * bpp;
|
||||||
|
|
||||||
|
// Compute hash of contents.
|
||||||
|
XXH3_state_t *hashState = XXH3_createState();
|
||||||
|
XXH3_64bits_reset(hashState);
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
XXH3_64bits_update(hashState, srcPixels + srcStrideInBytes, widthInBytes);
|
||||||
|
}
|
||||||
|
uint64_t imageHash = XXH3_64bits_digest(hashState);
|
||||||
|
XXH3_freeState(hashState);
|
||||||
|
|
||||||
// TODO: We can just change the texture format and flip some bits around instead of this.
|
// TODO: We can just change the texture format and flip some bits around instead of this.
|
||||||
// Could share code with the texture cache perhaps.
|
// Could share code with the texture cache perhaps.
|
||||||
auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) {
|
auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) {
|
||||||
@ -1396,16 +1408,28 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
|
|||||||
|
|
||||||
int frameNumber = draw_->GetFrameCount();
|
int frameNumber = draw_->GetFrameCount();
|
||||||
|
|
||||||
// Look for a matching texture we can re-use.
|
// First look for an exact match (including contents hash) that we can re-use.
|
||||||
|
for (auto &iter : drawPixelsCache_) {
|
||||||
|
if (iter.contentsHash == imageHash && iter.tex->Width() == width && iter.tex->Height() == height && iter.tex->Format() == texFormat) {
|
||||||
|
iter.frameNumber = frameNumber;
|
||||||
|
gpuStats.numCachedUploads++;
|
||||||
|
return iter.tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, look for an alternative one that's not been used recently that we can overwrite.
|
||||||
for (auto &iter : drawPixelsCache_) {
|
for (auto &iter : drawPixelsCache_) {
|
||||||
if (iter.frameNumber >= frameNumber - 3 || iter.tex->Width() != width || iter.tex->Height() != height || iter.tex->Format() != texFormat) {
|
if (iter.frameNumber >= frameNumber - 3 || iter.tex->Width() != width || iter.tex->Height() != height || iter.tex->Format() != texFormat) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OK, current one seems good, let's use it (and mark it used).
|
// OK, current one seems good, let's use it (and mark it used).
|
||||||
|
gpuStats.numUploads++;
|
||||||
draw_->UpdateTextureLevels(iter.tex, &srcPixels, generateTexture, 1);
|
draw_->UpdateTextureLevels(iter.tex, &srcPixels, generateTexture, 1);
|
||||||
// NOTE: numFlips is no good - this is called every frame when paused sometimes!
|
// NOTE: numFlips is no good - this is called every frame when paused sometimes!
|
||||||
iter.frameNumber = frameNumber;
|
iter.frameNumber = frameNumber;
|
||||||
|
// We need to update the hash for future matching.
|
||||||
|
iter.contentsHash = imageHash;
|
||||||
return iter.tex;
|
return iter.tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1435,8 +1459,9 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
|
|||||||
|
|
||||||
// INFO_LOG(G3D, "Creating drawPixelsCache texture: %dx%d", tex->Width(), tex->Height());
|
// INFO_LOG(G3D, "Creating drawPixelsCache texture: %dx%d", tex->Width(), tex->Height());
|
||||||
|
|
||||||
DrawPixelsEntry entry{ tex, frameNumber };
|
DrawPixelsEntry entry{ tex, imageHash, frameNumber };
|
||||||
drawPixelsCache_.push_back(entry);
|
drawPixelsCache_.push_back(entry);
|
||||||
|
gpuStats.numUploads++;
|
||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,6 +269,7 @@ class DrawContext;
|
|||||||
|
|
||||||
struct DrawPixelsEntry {
|
struct DrawPixelsEntry {
|
||||||
Draw::Texture *tex;
|
Draw::Texture *tex;
|
||||||
|
uint64_t contentsHash;
|
||||||
int frameNumber;
|
int frameNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@ struct GPUStatistics {
|
|||||||
numBlockingReadbacks = 0;
|
numBlockingReadbacks = 0;
|
||||||
numReadbacks = 0;
|
numReadbacks = 0;
|
||||||
numUploads = 0;
|
numUploads = 0;
|
||||||
|
numCachedUploads = 0;
|
||||||
numDepal = 0;
|
numDepal = 0;
|
||||||
numClears = 0;
|
numClears = 0;
|
||||||
numDepthCopies = 0;
|
numDepthCopies = 0;
|
||||||
@ -126,6 +127,7 @@ struct GPUStatistics {
|
|||||||
int numBlockingReadbacks;
|
int numBlockingReadbacks;
|
||||||
int numReadbacks;
|
int numReadbacks;
|
||||||
int numUploads;
|
int numUploads;
|
||||||
|
int numCachedUploads;
|
||||||
int numDepal;
|
int numDepal;
|
||||||
int numClears;
|
int numClears;
|
||||||
int numDepthCopies;
|
int numDepthCopies;
|
||||||
|
@ -1688,7 +1688,7 @@ size_t GPUCommonHW::FormatGPUStatsCommon(char *buffer, size_t size) {
|
|||||||
"Vertices: %d drawn: %d\n"
|
"Vertices: %d drawn: %d\n"
|
||||||
"FBOs active: %d (evaluations: %d)\n"
|
"FBOs active: %d (evaluations: %d)\n"
|
||||||
"Textures: %d, dec: %d, invalidated: %d, hashed: %d kB\n"
|
"Textures: %d, dec: %d, invalidated: %d, hashed: %d kB\n"
|
||||||
"readbacks %d (%d non-block), uploads %d, depal %d\n"
|
"readbacks %d (%d non-block), upload %d (cached %d), depal %d\n"
|
||||||
"block transfers: %d\n"
|
"block transfers: %d\n"
|
||||||
"replacer: tracks %d references, %d unique textures\n"
|
"replacer: tracks %d references, %d unique textures\n"
|
||||||
"Cpy: depth %d, color %d, reint %d, blend %d, self %d\n"
|
"Cpy: depth %d, color %d, reint %d, blend %d, self %d\n"
|
||||||
@ -1713,6 +1713,7 @@ size_t GPUCommonHW::FormatGPUStatsCommon(char *buffer, size_t size) {
|
|||||||
gpuStats.numBlockingReadbacks,
|
gpuStats.numBlockingReadbacks,
|
||||||
gpuStats.numReadbacks,
|
gpuStats.numReadbacks,
|
||||||
gpuStats.numUploads,
|
gpuStats.numUploads,
|
||||||
|
gpuStats.numCachedUploads,
|
||||||
gpuStats.numDepal,
|
gpuStats.numDepal,
|
||||||
gpuStats.numBlockTransfers,
|
gpuStats.numBlockTransfers,
|
||||||
gpuStats.numReplacerTrackedTex,
|
gpuStats.numReplacerTrackedTex,
|
||||||
|
@ -460,10 +460,10 @@ inline bool IsTextureFormat16Bit(GETextureFormat tfmt) {
|
|||||||
|
|
||||||
inline int BufferFormatBytesPerPixel(GEBufferFormat format) {
|
inline int BufferFormatBytesPerPixel(GEBufferFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case GE_FORMAT_8888: return 4; // applies to depth as well.
|
case GE_FORMAT_8888: return 4;
|
||||||
case GE_FORMAT_CLUT8: return 1;
|
case GE_FORMAT_CLUT8: return 1;
|
||||||
default:
|
default:
|
||||||
return 2;
|
return 2; // works for depth as well as the 16-bit color formats.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user