mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
test: release bitmaps in the HDR gain map pipeline test
Per Kotlin review: each test built a fresh 4000x3000 Ultra HDR fixture (~48 MB) and fully decoded large bitmaps without releasing them, which can flake with OOM on constrained CI devices. Recycle the fixture and every direct decode, gain map contents included (the gain map is a separate bitmap). Coil's bitmaps stay owned by Coil: shut the loaders down instead of recycling what their memory cache may hand out again.
This commit is contained in:
+46
-17
@@ -74,7 +74,12 @@ class HdrGainmapPipelineInstrumentedTest {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
assumeTrue("Gain maps need API 34+", Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
assumeTrue("Gain maps need API 34+", Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
hdrJpeg = File(appContext.cacheDir.also { it.mkdirs() }, "${UUID.randomUUID()}.jpg")
|
hdrJpeg = File(appContext.cacheDir.also { it.mkdirs() }, "${UUID.randomUUID()}.jpg")
|
||||||
hdrJpeg.outputStream().use { ultraHdrBitmap().compress(Bitmap.CompressFormat.JPEG, 95, it) }
|
val fixture = ultraHdrBitmap()
|
||||||
|
try {
|
||||||
|
hdrJpeg.outputStream().use { fixture.compress(Bitmap.CompressFormat.JPEG, 95, it) }
|
||||||
|
} finally {
|
||||||
|
fixture.recycleWithGainmap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -122,18 +127,24 @@ class HdrGainmapPipelineInstrumentedTest {
|
|||||||
@Test
|
@Test
|
||||||
fun coilDecodeKeepsTheGainmap() =
|
fun coilDecodeKeepsTheGainmap() =
|
||||||
runBlocking<Unit> {
|
runBlocking<Unit> {
|
||||||
|
// Coil owns the bitmaps it returns (its memory cache may hand them out again), so
|
||||||
|
// release them by shutting the loader down rather than recycling them here.
|
||||||
val loader = ImageLoader.Builder(appContext).build()
|
val loader = ImageLoader.Builder(appContext).build()
|
||||||
for (hardware in listOf(true, false)) {
|
try {
|
||||||
val request =
|
for (hardware in listOf(true, false)) {
|
||||||
ImageRequest
|
val request =
|
||||||
.Builder(appContext)
|
ImageRequest
|
||||||
.data(hdrJpeg)
|
.Builder(appContext)
|
||||||
.size(400, 300)
|
.data(hdrJpeg)
|
||||||
.allowHardware(hardware)
|
.size(400, 300)
|
||||||
.build()
|
.allowHardware(hardware)
|
||||||
val result = loader.execute(request) as SuccessResult
|
.build()
|
||||||
val bitmap = (result.image as BitmapImage).bitmap
|
val result = loader.execute(request) as SuccessResult
|
||||||
assertTrue("Coil dropped the gain map (allowHardware=$hardware)", bitmap.hasGainmap())
|
val bitmap = (result.image as BitmapImage).bitmap
|
||||||
|
assertTrue("Coil dropped the gain map (allowHardware=$hardware)", bitmap.hasGainmap())
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loader.shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,10 +188,14 @@ class HdrGainmapPipelineInstrumentedTest {
|
|||||||
assertTrue("gain map lost on a $expected load", (result.image as BitmapImage).bitmap.hasGainmap())
|
assertTrue("gain map lost on a $expected load", (result.image as BitmapImage).bitmap.hasGainmap())
|
||||||
}
|
}
|
||||||
|
|
||||||
load(DataSource.NETWORK)
|
try {
|
||||||
load(DataSource.MEMORY_CACHE)
|
load(DataSource.NETWORK)
|
||||||
memoryCache.clear()
|
load(DataSource.MEMORY_CACHE)
|
||||||
load(DataSource.DISK)
|
memoryCache.clear()
|
||||||
|
load(DataSource.DISK)
|
||||||
|
} finally {
|
||||||
|
loader.shutdown()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cacheDir.deleteRecursively()
|
cacheDir.deleteRecursively()
|
||||||
}
|
}
|
||||||
@@ -195,7 +210,21 @@ class HdrGainmapPipelineInstrumentedTest {
|
|||||||
|
|
||||||
private fun bounds(file: File) = BitmapFactory.Options().apply { inJustDecodeBounds = true }.also { BitmapFactory.decodeFile(file.absolutePath, it) }
|
private fun bounds(file: File) = BitmapFactory.Options().apply { inJustDecodeBounds = true }.also { BitmapFactory.decodeFile(file.absolutePath, it) }
|
||||||
|
|
||||||
private fun decodesWithGainmap(file: File): Boolean = BitmapFactory.decodeFile(file.absolutePath)?.hasGainmap() == true
|
// Full-size decodes of a 4000x3000 photo: recycle them rather than wait on the GC between tests.
|
||||||
|
private fun decodesWithGainmap(file: File): Boolean {
|
||||||
|
val bitmap = BitmapFactory.decodeFile(file.absolutePath) ?: return false
|
||||||
|
return try {
|
||||||
|
bitmap.hasGainmap()
|
||||||
|
} finally {
|
||||||
|
bitmap.recycleWithGainmap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The gain map is a separate bitmap; recycling the base does not free it.
|
||||||
|
private fun Bitmap.recycleWithGainmap() {
|
||||||
|
gainmap?.gainmapContents?.recycle()
|
||||||
|
recycle()
|
||||||
|
}
|
||||||
|
|
||||||
private fun serveForever(
|
private fun serveForever(
|
||||||
server: ServerSocket,
|
server: ServerSocket,
|
||||||
|
|||||||
Reference in New Issue
Block a user