@@ -1208,7 +1208,6 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
1208
1208
vfb ? vfb->bufferHeight : g_display.pixel_yres ,
1209
1209
u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
1210
1210
1211
- gpuStats.numUploads ++;
1212
1211
draw_->Invalidate (InvalidationFlags::CACHED_RENDER_STATE);
1213
1212
1214
1213
gstate_c.Dirty (DIRTY_ALL_RENDER_STATE);
@@ -1324,6 +1323,19 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
1324
1323
}
1325
1324
}
1326
1325
1326
+ int bpp = BufferFormatBytesPerPixel (srcPixelFormat);
1327
+ int srcStrideInBytes = srcStride * bpp;
1328
+ int widthInBytes = width * bpp;
1329
+
1330
+ // Compute hash of contents.
1331
+ XXH3_state_t *hashState = XXH3_createState ();
1332
+ XXH3_64bits_reset (hashState);
1333
+ for (int y = 0 ; y < height; y++) {
1334
+ XXH3_64bits_update (hashState, srcPixels + srcStrideInBytes, widthInBytes);
1335
+ }
1336
+ uint64_t imageHash = XXH3_64bits_digest (hashState);
1337
+ XXH3_freeState (hashState);
1338
+
1327
1339
// TODO: We can just change the texture format and flip some bits around instead of this.
1328
1340
// Could share code with the texture cache perhaps.
1329
1341
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
1396
1408
1397
1409
int frameNumber = draw_->GetFrameCount ();
1398
1410
1399
- // Look for a matching texture we can re-use.
1411
+ // First look for an exact match (including contents hash) that we can re-use.
1412
+ for (auto &iter : drawPixelsCache_) {
1413
+ if (iter.contentsHash == imageHash && iter.tex ->Width () == width && iter.tex ->Height () == height && iter.tex ->Format () == texFormat) {
1414
+ iter.frameNumber = frameNumber;
1415
+ gpuStats.numCachedUploads ++;
1416
+ return iter.tex ;
1417
+ }
1418
+ }
1419
+
1420
+ // Then, look for an alternative one that's not been used recently that we can overwrite.
1400
1421
for (auto &iter : drawPixelsCache_) {
1401
1422
if (iter.frameNumber >= frameNumber - 3 || iter.tex ->Width () != width || iter.tex ->Height () != height || iter.tex ->Format () != texFormat) {
1402
1423
continue ;
1403
1424
}
1404
1425
1405
1426
// OK, current one seems good, let's use it (and mark it used).
1427
+ gpuStats.numUploads ++;
1406
1428
draw_->UpdateTextureLevels (iter.tex , &srcPixels, generateTexture, 1 );
1407
1429
// NOTE: numFlips is no good - this is called every frame when paused sometimes!
1408
1430
iter.frameNumber = frameNumber;
1431
+ // We need to update the hash for future matching.
1432
+ iter.contentsHash = imageHash;
1409
1433
return iter.tex ;
1410
1434
}
1411
1435
@@ -1435,8 +1459,9 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
1435
1459
1436
1460
// INFO_LOG(G3D, "Creating drawPixelsCache texture: %dx%d", tex->Width(), tex->Height());
1437
1461
1438
- DrawPixelsEntry entry{ tex, frameNumber };
1462
+ DrawPixelsEntry entry{ tex, imageHash, frameNumber };
1439
1463
drawPixelsCache_.push_back (entry);
1464
+ gpuStats.numUploads ++;
1440
1465
return tex;
1441
1466
}
1442
1467
0 commit comments