Add FileChanged notification, use to reload data in image viewer

* Things will get weird if the image changes drastically like in format
  or dimension.
This commit is contained in:
baldurk
2015-07-15 22:06:33 +02:00
parent 2d8132943c
commit 0933d96fc9
11 changed files with 241 additions and 44 deletions
+4
View File
@@ -165,6 +165,8 @@ struct IReplayRenderer
virtual void Shutdown() = 0;
virtual void ShutdownOutput(ReplayOutput *output) = 0;
virtual void FileChanged() = 0;
virtual bool HasCallstacks() = 0;
virtual bool InitResolver() = 0;
@@ -230,6 +232,8 @@ extern "C" RENDERDOC_API ReplayOutput* RENDERDOC_CC ReplayRenderer_CreateOutput(
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRenderer *rend);
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(ReplayRenderer *rend, ReplayOutput *output);
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_FileChanged(ReplayRenderer *rend);
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_HasCallstacks(ReplayRenderer *rend);
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_InitResolver(ReplayRenderer *rend);
+178 -43
View File
@@ -33,8 +33,10 @@
class ImageViewer : public IReplayDriver
{
public:
ImageViewer(IReplayDriver *proxy, const char *filename, ResourceId texID)
ImageViewer(IReplayDriver *proxy, const char *filename)
: m_Proxy(proxy)
, m_Filename(filename)
, m_TextureID()
{
if(m_Proxy == NULL) RDCERR("Unexpectedly NULL proxy at creation of ImageViewer");
@@ -54,11 +56,13 @@ class ImageViewer : public IReplayDriver
d.name = filename;
record.drawcallList.push_back(d);
create_array_uninit(m_PipelineState.m_OM.RenderTargets, 1);
m_PipelineState.m_OM.RenderTargets[0].Resource = texID;
m_FrameRecord.push_back(record);
RefreshFile();
create_array_uninit(m_PipelineState.m_OM.RenderTargets, 1);
m_PipelineState.m_OM.RenderTargets[0].Resource = m_TextureID;
}
virtual ~ImageViewer()
@@ -83,22 +87,22 @@ class ImageViewer : public IReplayDriver
void RenderCheckerboard(Vec3f light, Vec3f dark) { m_Proxy->RenderCheckerboard(light, dark); }
void RenderHighlightBox(float w, float h, float scale) { m_Proxy->RenderHighlightBox(w, h, scale); }
bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, float *minval, float *maxval)
{ return m_Proxy->GetMinMax(texid, sliceFace, mip, sample, minval, maxval); }
{ return m_Proxy->GetMinMax(m_TextureID, sliceFace, mip, sample, minval, maxval); }
bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool channels[4], vector<uint32_t> &histogram)
{ return m_Proxy->GetHistogram(texid, sliceFace, mip, sample, minval, maxval, channels, histogram); }
bool RenderTexture(TextureDisplay cfg) { return m_Proxy->RenderTexture(cfg); }
{ return m_Proxy->GetHistogram(m_TextureID, sliceFace, mip, sample, minval, maxval, channels, histogram); }
bool RenderTexture(TextureDisplay cfg) { cfg.texid = m_TextureID; return m_Proxy->RenderTexture(cfg); }
void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4])
{ m_Proxy->PickPixel(texture, x, y, sliceFace, mip, sample, pixel); }
{ m_Proxy->PickPixel(m_TextureID, x, y, sliceFace, mip, sample, pixel); }
uint32_t PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y)
{ return m_Proxy->PickVertex(frameID, eventID, cfg, x, y); }
void BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors)
{ m_Proxy->BuildCustomShader(source, entry, compileFlags, type, id, errors); }
void FreeCustomShader(ResourceId id) { m_Proxy->FreeTargetResource(id); }
ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) { return m_Proxy->ApplyCustomShader(shader, texid, mip); }
ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) { return m_Proxy->ApplyCustomShader(shader, m_TextureID, mip); }
vector<ResourceId> GetTextures() { return m_Proxy->GetTextures(); }
FetchTexture GetTexture(ResourceId id) { return m_Proxy->GetTexture(id); }
FetchTexture GetTexture(ResourceId id) { return m_Proxy->GetTexture(m_TextureID); }
byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize)
{ return m_Proxy->GetTextureData(tex, arrayIdx, mip, resolve, forceRGBA8unorm, blackPoint, whitePoint, dataSize); }
{ return m_Proxy->GetTextureData(m_TextureID, arrayIdx, mip, resolve, forceRGBA8unorm, blackPoint, whitePoint, dataSize); }
// handle a couple of operations ourselves to return a simple fake log
APIProperties GetAPIProperties() { return m_Props; }
@@ -166,11 +170,21 @@ class ImageViewer : public IReplayDriver
RDCERR("Calling proxy-render functions on an image viewer");
}
void FileChanged()
{
RefreshFile();
}
private:
void RefreshFile();
APIProperties m_Props;
vector<FetchFrameRecord> m_FrameRecord;
D3D11PipelineState m_PipelineState;
IReplayDriver *m_Proxy;
string m_Filename;
ResourceId m_TextureID;
FetchTexture m_TexDetails;
};
ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
@@ -179,7 +193,112 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d
if(!f)
return eReplayCreate_FileIOFailed;
// 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;
int ret = LoadEXRFP(&data, &dummy, &dummy, f, &err);
if(data) free(data);
// 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);
return eReplayCreate_APIUnsupported;
}
}
else if(stbi_is_hdr_from_file(f))
{
FileIO::fseek64(f, 0, SEEK_SET);
int ignore = 0;
float *data = stbi_loadf_from_file(f, &ignore, &ignore, &ignore, 4);
if(!data)
{
FileIO::fclose(f);
RDCERR("HDR file recognised, but couldn't load with stbi_loadf_from_file");
return eReplayCreate_FileCorrupted;
}
free(data);
}
else if(is_dds_file(f))
{
FileIO::fseek64(f, 0, SEEK_SET);
dds_data read_data = load_dds_from_file(f);
if(read_data.subdata == NULL)
{
FileIO::fclose(f);
RDCERR("DDS file recognised, but couldn't load");
return eReplayCreate_FileCorrupted;
}
for(int i=0; i < read_data.slices*read_data.mips; i++)
delete[] read_data.subdata[i];
delete[] read_data.subdata;
delete[] read_data.subsizes;
}
else
{
int width = 0, height = 0;
int ignore = 0;
int ret = stbi_info_from_file(f, &width, &height, &ignore);
// just in case (we shouldn't have come in here if this weren't true), make sure
// the format is supported
if(ret == 0 ||
width == 0 || width == ~0U ||
height == 0 || height == ~0U)
{
FileIO::fclose(f);
return eReplayCreate_APIUnsupported;
}
byte *data = stbi_load_from_file(f, &ignore, &ignore, &ignore, 4);
if(!data)
{
FileIO::fclose(f);
RDCERR("File recognised, but couldn't load with stbi_load_from_file");
return eReplayCreate_FileCorrupted;
}
free(data);
}
FileIO::fclose(f);
IReplayDriver *proxy = NULL;
auto status = RenderDoc::Inst().CreateReplayDriver(RDC_Unknown, NULL, &proxy);
if(status != eReplayCreate_Success || !proxy)
{
if(proxy) proxy->Shutdown();
return status;
}
*driver = new ImageViewer(proxy, logfile);
return eReplayCreate_Success;
}
void ImageViewer::RefreshFile()
{
FILE *f = FileIO::fopen(m_Filename.c_str(), "rb");
FetchTexture texDetails;
ResourceFormat rgba8_unorm;
@@ -195,16 +314,19 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d
texDetails.creationFlags = eTextureCreate_SwapBuffer|eTextureCreate_RTV;
texDetails.cubemap = false;
texDetails.customName = true;
texDetails.name = logfile;
texDetails.ID = ResourceId();
texDetails.name = m_Filename;
texDetails.ID = m_TextureID;
texDetails.byteSize = 0;
texDetails.msQual = 0;
texDetails.msSamp = 1;
texDetails.format = rgba8_unorm;
// reasonable defaults for everything but dds
// reasonable defaults
texDetails.numSubresources = 1;
texDetails.dimension = 2;
texDetails.arraysize = 1;
texDetails.width = 1;
texDetails.height = 1;
texDetails.depth = 1;
texDetails.mips = 1;
@@ -229,7 +351,8 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d
{
if(data) free(data);
RDCERR("EXR file detected, but couldn't load with LoadEXR %d: '%s'", ret, err);
return eReplayCreate_APIUnsupported;
FileIO::fclose(f);
return;
}
}
else if(stbi_is_hdr_from_file(f))
@@ -257,7 +380,8 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d
texDetails.width == 0 || texDetails.width == ~0U ||
texDetails.height == 0 || texDetails.height == ~0U)
{
return eReplayCreate_APIUnsupported;
FileIO::fclose(f);
return;
}
texDetails.format = rgba8_unorm;
@@ -270,36 +394,21 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d
// file was corrupted and we failed to load it
if(!dds && data == NULL)
{
return eReplayCreate_FileCorrupted;
}
IReplayDriver *proxy = NULL;
auto status = RenderDoc::Inst().CreateReplayDriver(RDC_Unknown, NULL, &proxy);
if(status != eReplayCreate_Success || !proxy)
{
if(proxy) proxy->Shutdown();
return status;
FileIO::fclose(f);
return;
}
ResourceId id;
dds_data read_data;
if(!dds)
{
id = proxy->CreateProxyTexture(texDetails);
proxy->SetProxyTextureData(id, 0, 0, data, datasize);
free(data);
}
else
if(dds)
{
FileIO::fseek64(f, 0, SEEK_SET);
dds_data read_data = load_dds_from_file(f);
if(read_data.subdata == NULL)
{
proxy->Shutdown();
return eReplayCreate_FileCorrupted;
FileIO::fclose(f);
return;
}
texDetails.cubemap = read_data.cubemap;
@@ -313,12 +422,42 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d
texDetails.dimension = 1;
if(texDetails.width > 1) texDetails.dimension = 2;
if(texDetails.depth > 1) texDetails.dimension = 3;
}
id = proxy->CreateProxyTexture(texDetails);
// recreate proxy texture if necessary.
// we rewrite the texture IDs so that the
// outside world doesn't need to know about this
// (we only ever have one texture in the image
// viewer so we can just set all texture IDs
// used to that).
if(m_TextureID != ResourceId())
{
if(m_TexDetails.width != texDetails.width ||
m_TexDetails.height != texDetails.height ||
m_TexDetails.depth != texDetails.depth ||
m_TexDetails.cubemap != texDetails.cubemap ||
m_TexDetails.mips != texDetails.mips ||
m_TexDetails.arraysize != texDetails.arraysize ||
m_TexDetails.width != texDetails.width ||
m_TexDetails.format != texDetails.format)
{
m_TextureID = ResourceId();
}
}
if(m_TextureID == ResourceId())
m_TextureID = m_Proxy->CreateProxyTexture(texDetails);
if(!dds)
{
m_Proxy->SetProxyTextureData(m_TextureID, 0, 0, data, datasize);
free(data);
}
else
{
for(uint32_t i=0; i < texDetails.numSubresources; i++)
{
proxy->SetProxyTextureData(id, i/texDetails.mips, i%texDetails.mips, read_data.subdata[i], (size_t)read_data.subsizes[i]);
m_Proxy->SetProxyTextureData(m_TextureID, i/texDetails.mips, i%texDetails.mips, read_data.subdata[i], (size_t)read_data.subsizes[i]);
delete[] read_data.subdata[i];
}
@@ -327,11 +466,7 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d
delete[] read_data.subsizes;
}
*driver = new ImageViewer(proxy, logfile, id);
FileIO::fclose(f);
return eReplayCreate_Success;
}
static DriverRegistration IMGDriverRegistration(RDC_Image, "Image", &IMG_CreateReplayDevice);
+2
View File
@@ -373,6 +373,8 @@ class ProxySerialiser : public IReplayDriver, Callstack::StackResolver
void ReplaceResource(ResourceId from, ResourceId to);
void RemoveReplacement(ResourceId id);
void FileChanged() {}
// will never be used
ResourceId CreateProxyTexture(FetchTexture templateTex)
{
+8
View File
@@ -45,6 +45,10 @@ D3D11Replay::D3D11Replay()
void D3D11Replay::Shutdown()
{
for(size_t i=0; i < m_ProxyResources.size(); i++)
m_ProxyResources[i]->Release();
m_ProxyResources.clear();
m_pDevice->Release();
D3D11DebugManager::PostDeviceShutdownCounters();
@@ -1547,6 +1551,8 @@ ResourceId D3D11Replay::CreateProxyTexture(FetchTexture templateTex)
SetDebugName(resource, templateTex.name.elems);
}
m_ProxyResources.push_back(resource);
return ret;
}
@@ -1694,6 +1700,8 @@ ResourceId D3D11Replay::CreateProxyBuffer(FetchBuffer templateBuf)
SetDebugName(resource, templateBuf.name.elems);
}
m_ProxyResources.push_back(resource);
return ret;
}
+4
View File
@@ -129,6 +129,8 @@ class D3D11Replay : public IReplayDriver
ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip);
bool IsRenderOutput(ResourceId id);
void FileChanged() {}
void InitCallstackResolver();
bool HasCallstacks();
@@ -139,6 +141,8 @@ class D3D11Replay : public IReplayDriver
bool m_WARP;
bool m_Proxy;
vector<ID3D11Resource*> m_ProxyResources;
WrappedID3D11Device *m_pDevice;
D3D11PipelineState m_CurPipelineState;
+2
View File
@@ -177,6 +177,8 @@ class GLReplay : public IReplayDriver
void SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize);
bool IsRenderOutput(ResourceId id);
void FileChanged() {}
void InitCallstackResolver();
bool HasCallstacks();
+2
View File
@@ -105,6 +105,8 @@ class IRemoteDriver
virtual ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector<uint32_t> &passEvents) = 0;
virtual bool IsRenderOutput(ResourceId id) = 0;
virtual void FileChanged() = 0;
virtual void InitCallstackResolver() = 0;
virtual bool HasCallstacks() = 0;
+8
View File
@@ -1475,6 +1475,11 @@ FetchDrawcall *ReplayRenderer::SetupDrawcallPointers(FetchFrameInfo frame, rdcty
return ret;
}
void ReplayRenderer::FileChanged()
{
m_pDevice->FileChanged();
}
bool ReplayRenderer::HasCallstacks()
{
return m_pDevice->HasCallstacks();
@@ -1523,6 +1528,9 @@ extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_Shutdown(ReplayRendere
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(ReplayRenderer *rend, ReplayOutput *output)
{ rend->ShutdownOutput(output); }
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_FileChanged(ReplayRenderer *rend)
{ rend->FileChanged(); }
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_HasCallstacks(ReplayRenderer *rend)
{ return rend->HasCallstacks(); }
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_InitResolver(ReplayRenderer *rend)
+3 -1
View File
@@ -133,7 +133,9 @@ struct ReplayRenderer : public IReplayRenderer
ReplayCreateStatus CreateDevice(const char *logfile);
ReplayCreateStatus SetDevice(IReplayDriver *device);
void FileChanged();
bool HasCallstacks();
bool InitResolver();
+24
View File
@@ -58,6 +58,8 @@ namespace renderdocui.Code
private bool m_LogLoaded = false;
private FileSystemWatcher m_LogWatcher = null;
private string m_LogFile = "";
private UInt32 m_FrameID = 0;
@@ -529,6 +531,13 @@ namespace renderdocui.Code
m_LogLoaded = true;
progressThread = false;
m_LogWatcher = new FileSystemWatcher(Path.GetDirectoryName(m_LogFile), Path.GetFileName(m_LogFile));
m_LogWatcher.EnableRaisingEvents = true;
m_LogWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite;
m_LogWatcher.Created += new FileSystemEventHandler(OnLogfileChanged);
m_LogWatcher.Changed += new FileSystemEventHandler(OnLogfileChanged);
m_LogWatcher.SynchronizingObject = m_MainWindow; // callbacks on UI thread please
List<ILogViewerForm> logviewers = new List<ILogViewerForm>();
logviewers.AddRange(m_LogViewers);
@@ -566,6 +575,17 @@ namespace renderdocui.Code
p.LogfileProgress(1.0f);
}
void OnLogfileChanged(object sender, FileSystemEventArgs e)
{
m_Renderer.Invoke((ReplayRenderer r) =>
{
r.FileChanged();
r.SetFrameEvent(m_FrameID, m_EventID > 0 ? m_EventID-1 : 1);
});
SetEventID(null, CurFrame, CurEvent);
}
public void CloseLogfile()
{
if (!m_LogLoaded) return;
@@ -590,6 +610,10 @@ namespace renderdocui.Code
m_LogLoaded = false;
if (m_LogWatcher != null)
m_LogWatcher.EnableRaisingEvents = false;
m_LogWatcher = null;
foreach (var logviewer in m_LogViewers)
{
Control c = (Control)logviewer;
+6
View File
@@ -185,6 +185,9 @@ namespace renderdoc
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern void ReplayRenderer_ShutdownOutput(IntPtr real, IntPtr replayOutput);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern void ReplayRenderer_FileChanged(IntPtr real);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern bool ReplayRenderer_HasCallstacks(IntPtr real);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
@@ -301,6 +304,9 @@ namespace renderdoc
return new ReplayOutput(ret);
}
public void FileChanged()
{ ReplayRenderer_FileChanged(m_Real); }
public bool HasCallstacks()
{ return ReplayRenderer_HasCallstacks(m_Real); }