From 1ed69916c927548d3aaeacdc4963bee54bf673aa Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 7 Apr 2016 00:55:30 +0200 Subject: [PATCH] Use the new tinyexr API for memory load/save instead of manual additions --- renderdoc/core/image_viewer.cpp | 92 +++++++++++++++++++++++----- renderdoc/replay/replay_renderer.cpp | 74 +++++++++++++++++++--- 2 files changed, 143 insertions(+), 23 deletions(-) diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index cfd369bea..d1150fc4d 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -200,23 +200,30 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d // make sure the file is a type we recognise before going further if(is_exr_file(f)) { - FileIO::fseek64(f, 0, SEEK_SET); - const char *err = NULL; - float *data = NULL; - int dummy; + FileIO::fseek64(f, 0, SEEK_END); + uint64_t size = FileIO::ftell64(f); + FileIO::fseek64(f, 0, SEEK_SET); - int ret = LoadEXRFP(&data, &dummy, &dummy, f, &err); + std::vector buffer; + buffer.resize((size_t)size); - if(data) free(data); + FileIO::fread(&buffer[0], 1, buffer.size(), f); + + EXRImage exrImage; + InitEXRImage(&exrImage); + + int ret = ParseMultiChannelEXRHeaderFromMemory(&exrImage, &buffer[0], &err); + + FreeEXRImage(&exrImage); // could be an unsupported form of EXR, like deep image or other if(ret != 0) { FileIO::fclose(f); - RDCERR("EXR file detected, but couldn't load with LoadEXR %d: '%s'", ret, err); + RDCERR("EXR file detected, but couldn't load with ParseMultiChannelEXRHeaderFromMemory %d: '%s'", ret, err); return eReplayCreate_APIUnsupported; } } @@ -355,20 +362,77 @@ void ImageViewer::RefreshFile() if(is_exr_file(f)) { texDetails.format = rgba32_float; - + + FileIO::fseek64(f, 0, SEEK_END); + uint64_t size = FileIO::ftell64(f); FileIO::fseek64(f, 0, SEEK_SET); + std::vector buffer; + buffer.resize((size_t)size); + + FileIO::fread(&buffer[0], 1, buffer.size(), f); + + FileIO::fclose(f); + + EXRImage exrImage; + InitEXRImage(&exrImage); + const char *err = NULL; - int ret = LoadEXRFP((float **)&data, (int *)&texDetails.width, (int *)&texDetails.height, f, &err); - datasize = texDetails.width*texDetails.height*4*sizeof(float); + int ret = ParseMultiChannelEXRHeaderFromMemory(&exrImage, &buffer[0], &err); - // could be an unsupported form of EXR, like deep image or other if(ret != 0) { - if(data) free(data); - RDCERR("EXR file detected, but couldn't load with LoadEXR %d: '%s'", ret, err); - FileIO::fclose(f); + RDCERR("EXR file detected, but couldn't load with ParseMultiChannelEXRHeaderFromMemory %d: '%s'", ret, err); + return; + } + + texDetails.width = exrImage.width; + texDetails.height = exrImage.height; + + datasize = texDetails.width*texDetails.height*4*sizeof(float); + data = (byte *)malloc(datasize); + + for(int i=0; i < exrImage.num_channels; i++) + exrImage.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + + ret = LoadMultiChannelEXRFromMemory(&exrImage, &buffer[0], &err); + + int channels[4] = { -1, -1, -1, -1 }; + for(int i=0; i < exrImage.num_channels; i++) + { + switch(exrImage.channel_names[i][0]) + { + case 'R': channels[0] = i; break; + case 'G': channels[1] = i; break; + case 'B': channels[2] = i; break; + case 'A': channels[3] = i; break; + } + } + + float *rgba = (float *)data; + float **src = (float **)exrImage.images; + + for(uint32_t i=0; i < texDetails.width*texDetails.height; i++) + { + for(int c=0; c < 4; c++) + { + if(channels[c] >= 0) + rgba[i*4 + c] = src[ channels[c] ][i]; + else if(c < 3) // RGB channels default to 0 + rgba[i*4 + c] = 0.0f; + else // alpha defaults to 1 + rgba[i*4 + c] = 1.0f; + } + } + + FreeEXRImage(&exrImage); + + // shouldn't get here but let's be safe + if(ret != 0) + { + free(data); + RDCERR("EXR file detected, but couldn't load with LoadEXRFromMemory %d: '%s'", ret, err); return; } } diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index e62fe48d4..cb92b31bc 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -1045,7 +1045,20 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) } else if(sd.destType == eFileType_HDR || sd.destType == eFileType_EXR) { - float *fldata = new float[td.width*td.height*4]; + float *fldata = NULL; + float *bgra[4] = { NULL, NULL, NULL, NULL }; + + if(sd.destType == eFileType_HDR) + { + fldata = new float[td.width*td.height*4]; + } + else + { + bgra[0] = new float[td.width*td.height]; + bgra[1] = new float[td.width*td.height]; + bgra[2] = new float[td.width*td.height]; + bgra[3] = new float[td.width*td.height]; + } byte *srcData = subdata[0]; @@ -1124,10 +1137,20 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) r = g = b = a; a = 1.0f; } - fldata[(y*td.width + x) * 4 + 0] = r; - fldata[(y*td.width + x) * 4 + 1] = g; - fldata[(y*td.width + x) * 4 + 2] = b; - fldata[(y*td.width + x) * 4 + 3] = a; + if(fldata) + { + fldata[(y*td.width + x) * 4 + 0] = r; + fldata[(y*td.width + x) * 4 + 1] = g; + fldata[(y*td.width + x) * 4 + 2] = b; + fldata[(y*td.width + x) * 4 + 3] = a; + } + else + { + bgra[0][(y*td.width + x)] = b; + bgra[1][(y*td.width + x)] = g; + bgra[2][(y*td.width + x)] = r; + bgra[3][(y*td.width + x)] = a; + } } } @@ -1139,13 +1162,46 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) else if(sd.destType == eFileType_EXR) { const char *err = NULL; - int ret = SaveEXRFP(fldata, (int)td.width, (int)td.height, f, &err); - success = (ret == 0); - if(!success) + + EXRImage exrImage; + InitEXRImage(&exrImage); + + int pixTypes[4] = { TINYEXR_PIXELTYPE_FLOAT, TINYEXR_PIXELTYPE_FLOAT, TINYEXR_PIXELTYPE_FLOAT, TINYEXR_PIXELTYPE_FLOAT }; + int reqTypes[4] = { TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF }; + const char *bgraNames[4] = { "B", "G", "R", "A" }; + + exrImage.num_channels = 4; + exrImage.channel_names = bgraNames; + exrImage.images = (unsigned char**)bgra; + exrImage.width = td.width; + exrImage.height = td.height; + exrImage.pixel_types = pixTypes; + exrImage.requested_pixel_types = reqTypes; + + unsigned char *mem = NULL; + + size_t ret = SaveMultiChannelEXRToMemory(&exrImage, &mem, &err); + + success = (ret > 0); + if(success) + FileIO::fwrite(mem, 1, ret, f); + else RDCERR("Error saving EXR file %d: '%s'", ret, err); + + free(mem); } - delete[] fldata; + if(fldata) + { + delete[] fldata; + } + else + { + delete[] bgra[0]; + delete[] bgra[1]; + delete[] bgra[2]; + delete[] bgra[3]; + } } FileIO::fclose(f);