Move capture-file handling functions into a single interface

* This allows us to return complex types like byte arrays or pairs of
  status & render handle.
* Also in future more introspection of the capture file will be possible
  and this provides an easy extension to that without adding new entry
  points.
This commit is contained in:
baldurk
2017-04-18 14:57:47 +01:00
parent dd1e090040
commit a7ab0d9300
13 changed files with 492 additions and 249 deletions
+1 -1
View File
@@ -5,4 +5,4 @@ Enums and Data Structures
:members:
:undoc-members:
:imported-members:
:exclude-members: free_functions__, enum_constants__, name_match__startswith__D3D11_, name_match__startswith__D3D12_, name_match__startswith__VK_, name_match__startswith__GL_, str, ReplayRenderer, ReplayOutput, TargetControl, RemoteServer
:exclude-members: free_functions__, enum_constants__, name_match__startswith__D3D11_, name_match__startswith__D3D12_, name_match__startswith__VK_, name_match__startswith__GL_, str, ReplayRenderer, ReplayOutput, TargetControl, RemoteServer, CaptureFile
+42 -21
View File
@@ -1,33 +1,54 @@
Functions
=========
.. contents::
.. module:: renderdoc
Capture File Access
-------------------
.. autofunction:: renderdoc.OpenCaptureFile
Target Control
--------------
.. autofunction:: renderdoc.EnumerateRemoteTargets
.. autofunction:: renderdoc.CreateTargetControl
Remote Servers
--------------
.. autofunction:: renderdoc.CreateRemoteServerConnection
.. autofunction:: renderdoc.GetDefaultRemoteServerPort
.. autofunction:: renderdoc.BecomeRemoteServer
Local Execution & Injection
---------------------------
.. autofunction:: renderdoc.GetDefaultCaptureOptions
.. autofunction:: renderdoc.ExecuteAndInject
.. autofunction:: renderdoc.InjectIntoProcess
.. autofunction:: renderdoc.StartGlobalHook
Logging & Versioning
--------------------
.. autofunction:: renderdoc.SetDebugLogFile
.. autofunction:: renderdoc.GetLogFile
.. autofunction:: renderdoc.GetVersionString
.. autofunction:: renderdoc.GetCommitHash
Maths & Utilities
-----------------
.. autofunction:: renderdoc.Maths_FloatToHalf
.. autofunction:: renderdoc.Maths_HalfToFloat
.. autofunction:: renderdoc.Topology_NumVerticesPerPrimitive
.. autofunction:: renderdoc.Topology_VertexOffset
.. autofunction:: renderdoc.SupportLocalReplay
.. autofunction:: renderdoc.CreateReplayRenderer
.. autofunction:: renderdoc.CreateTargetControl
.. autofunction:: renderdoc.EnumerateRemoteTargets
.. autofunction:: renderdoc.GetDefaultRemoteServerPort
.. autofunction:: renderdoc.CreateRemoteServerConnection
.. autofunction:: renderdoc.BecomeRemoteServer
.. autofunction:: renderdoc.GetDefaultCaptureOptions
.. autofunction:: renderdoc.StartGlobalHook
.. autofunction:: renderdoc.ExecuteAndInject
.. autofunction:: renderdoc.InjectIntoProcess
.. autofunction:: renderdoc.StartSelfHostCapture
.. autofunction:: renderdoc.EndSelfHostCapture
.. autofunction:: renderdoc.SetDebugLogFile
.. autofunction:: renderdoc.GetLogFile
.. autofunction:: renderdoc.GetThumbnail
.. autofunction:: renderdoc.GetVersionString
.. autofunction:: renderdoc.GetCommitHash
.. autofunction:: renderdoc.IsD3D
.. autofunction:: renderdoc.PatchList_Count
.. autofunction:: renderdoc.PatchList_Topology
.. autofunction:: renderdoc.IsD3D
.. autofunction:: renderdoc.MaskForStage
.. autofunction:: renderdoc.StartSelfHostCapture
.. autofunction:: renderdoc.EndSelfHostCapture
+21
View File
@@ -1,20 +1,41 @@
Primary Interfaces
==================
.. contents::
.. module:: renderdoc
ReplayRenderer
--------------
.. autoclass:: renderdoc.ReplayRenderer
:members:
:undoc-members:
ReplayOutput
------------
.. autoclass:: renderdoc.ReplayOutput
:members:
:undoc-members:
TargetControl
-------------
.. autoclass:: renderdoc.TargetControl
:members:
:undoc-members:
RemoteServer
------------
.. autoclass:: renderdoc.RemoteServer
:members:
:undoc-members:
CaptureFile
-----------
.. autoclass:: renderdoc.CaptureFile
:members:
:undoc-members:
+12 -1
View File
@@ -396,10 +396,21 @@ void RenderManager::run()
IReplayRenderer *renderer = NULL;
if(m_Remote)
{
std::tie(m_CreateStatus, renderer) =
m_Remote->OpenCapture(~0U, m_Logfile.toUtf8().data(), m_Progress);
}
else
m_CreateStatus = RENDERDOC_CreateReplayRenderer(m_Logfile.toUtf8().data(), m_Progress, &renderer);
{
ICaptureFile *file = RENDERDOC_OpenCaptureFile(m_Logfile.toUtf8().data());
m_CreateStatus = file->OpenStatus();
if(m_CreateStatus == ReplayStatus::Succeeded)
std::tie(m_CreateStatus, renderer) = file->OpenCapture(m_Progress);
file->Shutdown();
}
if(renderer == NULL)
return;
+22 -7
View File
@@ -411,8 +411,8 @@ void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local
if(m_Ctx.LogLoading())
return;
rdctype::str driver;
rdctype::str machineIdent;
QString driver;
QString machineIdent;
ReplaySupport support = ReplaySupport::Unsupported;
bool remoteReplay =
@@ -420,7 +420,22 @@ void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local
if(local)
{
support = RENDERDOC_SupportLocalReplay(filename.toUtf8().data(), &driver, &machineIdent);
ICaptureFile *file = RENDERDOC_OpenCaptureFile(filename.toUtf8().data());
if(file->OpenStatus() != ReplayStatus::Succeeded)
{
RDDialog::critical(NULL, tr("Error opening capture"),
tr("Couldn't open file '%1'").arg(filename));
file->Shutdown();
return;
}
driver = QString::fromUtf8(file->DriverName());
machineIdent = QString::fromUtf8(file->RecordedMachineIdent());
support = file->LocalReplaySupport();
file->Shutdown();
// if the return value suggests remote replay, and it's not already selected, AND the user
// hasn't previously chosen to always replay locally without being prompted, ask if they'd
@@ -428,7 +443,7 @@ void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local
if(support == ReplaySupport::SuggestRemote && !remoteReplay &&
!m_Ctx.Config().AlwaysReplayLocally)
{
SuggestRemoteDialog dialog(ToQStr(driver), ToQStr(machineIdent), this);
SuggestRemoteDialog dialog(driver, machineIdent, this);
FillRemotesMenu(dialog.remotesMenu(), false);
@@ -499,13 +514,13 @@ void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local
// if driver is empty something went wrong loading the log, let it be handled as usual
// below. Otherwise indicate that support is missing.
if(driver.count > 0 && support == ReplaySupport::Unsupported)
if(!driver.isEmpty() && support == ReplaySupport::Unsupported)
{
if(remoteReplay)
{
QString remoteMessage =
tr("This log was captured with %1 and cannot be replayed on %2.\n\n")
.arg(driver.c_str())
.arg(driver)
.arg(m_Ctx.Renderer().CurrentRemote()->Hostname);
remoteMessage += "Try selecting a different remote context in the status bar.";
@@ -515,7 +530,7 @@ void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local
else
{
QString remoteMessage =
tr("This log was captured with %1 and cannot be replayed locally.\n\n").arg(driver.c_str());
tr("This log was captured with %1 and cannot be replayed locally.\n\n").arg(driver);
remoteMessage += "Try selecting a remote context in the status bar.";
+1
View File
@@ -113,6 +113,7 @@ set(sources
os/os_specific.h
replay/app_api.cpp
replay/capture_options.cpp
replay/capture_file.cpp
replay/entry_points.cpp
replay/replay_driver.h
replay/replay_output.cpp
+87 -38
View File
@@ -1019,6 +1019,84 @@ protected:
~IRemoteServer() = default;
};
DOCUMENT(R"(A handle to a capture file. Used for simple cheap processing and meta-data fetching
without opening the capture for analysis.
)")
struct ICaptureFile
{
DOCUMENT("Closes the handle.");
virtual void Shutdown() = 0;
DOCUMENT(R"(Retrieves the status of the handle.
This returns an error if the capture file used to create the handle wasn't found, or was corrupted,
or something else went wrong while processing it.
:return: The status of the handle to the file.
:rtype: ReplayStatus
)");
virtual ReplayStatus OpenStatus() = 0;
DOCUMENT(R"(Retrieves the filename used to open this handle.
This filename is exactly as specified without any modificaton to make it an absolute path.
:return: The filename used to create this handle.
:rtype: ``str``
)");
virtual const char *Filename() = 0;
DOCUMENT(R"(Queries for how well a particular capture is supported on the local machine.
:return: How much support for replay exists locally.
:rtype: ReplaySupport
)");
virtual ReplaySupport LocalReplaySupport() = 0;
DOCUMENT(R"(Retrieves the name of the driver that was used to create this capture.
:return: A simple string identifying the driver used to make the capture.
:rtype: ``str``
)");
virtual const char *DriverName() = 0;
DOCUMENT(R"(Retrieves the identifying string describing what type of machine created this capture.
:return: A string identifying the machine ident used to make the capture.
:rtype: ``str``
)");
virtual const char *RecordedMachineIdent() = 0;
DOCUMENT(R"(Opens a capture for replay locally and returns a handle to the capture.
This function will block until the capture is fully loaded and ready.
Once the replay is created, this :class:`CaptureFile` can be shut down, there is no dependency on it
by the :class:`ReplayRenderer`.
:param float progress: A reference to a ``float`` value that will be updated as the copy happens
from ``0.0`` to ``1.0``. The parameter can be ``None`` if no progress update is desired.
:return: A tuple containing the status of opening the capture, whether success or failure, and the
resulting :class:`ReplayRenderer` handle if successful.
:rtype: ``tuple`` of :class:`ReplayStatus` and :class:`ReplayRenderer`.
)");
virtual rdctype::pair<ReplayStatus, IReplayRenderer *> OpenCapture(float *progress) = 0;
DOCUMENT(R"(Retrieves the embedded thumbnail from the capture.
:param FileType type: The image format to convert the thumbnail to.
:param int maxsize: The largest width or height allowed. If the thumbnail is larger, it's resized.
:return: The raw contents of the thumbnail, converted to the desired type at the desired max
resolution.
:rtype: ``bytes``.
)");
virtual rdctype::array<byte> GetThumbnail(FileType type, uint32_t maxsize) = 0;
protected:
ICaptureFile() = default;
~ICaptureFile() = default;
};
//////////////////////////////////////////////////////////////////////////
// camera
//////////////////////////////////////////////////////////////////////////
@@ -1091,39 +1169,21 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC Topology_VertexOffset(Topology to
uint32_t primitive);
//////////////////////////////////////////////////////////////////////////
// Create a replay renderer, for playback and analysis.
// Create a capture handle.
//
// Takes the filename of the log. Returns NULL in the case of any error.
// Takes the filename of the log. Always returns a valid handle that must be shut down.
// If any errors happen this can be queried with :meth:`CaptureFile.Status`.
//////////////////////////////////////////////////////////////////////////
DOCUMENT(R"(Queries for how well a particular capture is supported on the local machine, and returns
some simple properties about the capture.
DOCUMENT(R"(Create a capture handle.
:param str path: The path to the capture.
:param str driverName: A reference to a ``str`` that is filled with the name of the driver used in
the capture.
:param str driverName: A reference to a ``str`` that is filled with the identifier of the type of
machine used such as OS and architecture.
:return: How much support for replay exists locally.
Takes the filename of the log. This function *always* returns a valid handle that must be shut down.
If any errors happen this can be queried with :meth:`CaptureFile.Status`.
:return: A handle to the specified path.
:rtype: ReplaySupport
)");
extern "C" RENDERDOC_API ReplaySupport RENDERDOC_CC RENDERDOC_SupportLocalReplay(
const char *logfile, rdctype::str *driverName, rdctype::str *recordMachineIdent);
DOCUMENT(R"(Opens a capture for replay locally and returns a handle to the capture.
This function will block until the capture is fully loaded and ready.
:param str logfile: The path to the capture.
:param float progress: A reference to a ``float`` value that will be updated as the copy happens
from ``0.0`` to ``1.0``.
:param ReplayRenderer rend: A reference to a :class:`ReplayRenderer` where the capture handle will
be stored.
:return: The status of opening the capture, whether success or failure.
:rtype: ReplayStatus
)");
extern "C" RENDERDOC_API ReplayStatus RENDERDOC_CC
RENDERDOC_CreateReplayRenderer(const char *logfile, float *progress, IReplayRenderer **rend);
extern "C" RENDERDOC_API ICaptureFile *RENDERDOC_CC RENDERDOC_OpenCaptureFile(const char *logfile);
//////////////////////////////////////////////////////////////////////////
// Target Control
@@ -1315,17 +1375,6 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_LogMessage(LogType type, co
const char *file, unsigned int line,
const char *text);
DOCUMENT(R"(Retrieves the embedded thumbnail from a capture.
:param str filename: The filename of the capture to open.
:param FileType type: The image format to convert the thumbnail to.
:param int maxsize: The largest width or height allowed. If the thumbnail is larger, it's resized.
:param bytes buf: A reference to a ``bytes`` to receive the data, empty if something went wrong.
)");
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *filename,
FileType type, uint32_t maxsize,
rdctype::array<byte> *buf);
DOCUMENT(R"(Retrieves the version string.
This will be in the form "MAJOR.MINOR"
+7 -1
View File
@@ -128,7 +128,13 @@ void RenderDoc::TargetControlClientThread(void *s)
ser.Serialise("", path);
rdctype::array<byte> buf;
RENDERDOC_GetThumbnail(captures.back().path.c_str(), FileType::JPG, 0, &buf);
ICaptureFile *file = RENDERDOC_OpenCaptureFile(captures.back().path.c_str());
if(file->OpenStatus() == ReplayStatus::Succeeded)
{
buf = file->GetThumbnail(FileType::JPG, 0);
}
file->Shutdown();
size_t sz = buf.size();
ser.Serialise("", buf.count);
+1
View File
@@ -385,6 +385,7 @@
<ClCompile Include="os\win32\win32_stringio.cpp" />
<ClCompile Include="os\win32\win32_threading.cpp" />
<ClCompile Include="replay\app_api.cpp" />
<ClCompile Include="replay\capture_file.cpp" />
<ClCompile Include="replay\capture_options.cpp" />
<ClCompile Include="replay\entry_points.cpp" />
<ClCompile Include="replay\replay_output.cpp" />
+3
View File
@@ -452,6 +452,9 @@
<ClCompile Include="3rdparty\tinyfiledialogs\tinyfiledialogs.c">
<Filter>3rdparty\tinyfiledialogs</Filter>
</ClCompile>
<ClCompile Include="replay\capture_file.cpp">
<Filter>Replay</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="os\win32\comexport.def">
+249
View File
@@ -0,0 +1,249 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "api/replay/renderdoc_replay.h"
#include "core/core.h"
#include "jpeg-compressor/jpgd.h"
#include "jpeg-compressor/jpge.h"
#include "replay/replay_renderer.h"
#include "serialise/serialiser.h"
#include "stb/stb_image_resize.h"
#include "stb/stb_image_write.h"
static void writeToByteVector(void *context, void *data, int size)
{
std::vector<byte> *vec = (std::vector<byte> *)context;
byte *start = (byte *)data;
byte *end = start + size;
vec->insert(vec->end(), start, end);
}
class CaptureFile : public ICaptureFile
{
public:
CaptureFile(const char *f);
virtual ~CaptureFile() {}
void Shutdown() { delete this; }
ReplayStatus OpenStatus() { return m_Status; }
const char *Filename() { return m_Filename.c_str(); }
ReplaySupport LocalReplaySupport() { return m_Support; }
const char *DriverName() { return m_DriverName.c_str(); }
const char *RecordedMachineIdent() { return m_Ident.c_str(); }
rdctype::pair<ReplayStatus, IReplayRenderer *> OpenCapture(float *progress);
rdctype::array<byte> GetThumbnail(FileType type, uint32_t maxsize);
private:
std::string m_Filename, m_DriverName, m_Ident;
RDCDriver m_DriverType;
ReplayStatus m_Status;
ReplaySupport m_Support;
};
CaptureFile::CaptureFile(const char *f)
{
m_Filename = f;
m_DriverType = RDC_Unknown;
uint64_t fileMachineIdent = 0;
m_Status = RenderDoc::Inst().FillInitParams(Filename(), m_DriverType, m_DriverName,
fileMachineIdent, NULL);
if(m_Status != ReplayStatus::Succeeded)
{
m_Support = ReplaySupport::Unsupported;
}
else
{
m_Support = RenderDoc::Inst().HasReplayDriver(m_DriverType) ? ReplaySupport::Supported
: ReplaySupport::Unsupported;
if(fileMachineIdent != 0)
{
uint64_t machineIdent = OSUtility::GetMachineIdent();
m_Ident = OSUtility::MakeMachineIdentString(fileMachineIdent);
if((machineIdent & OSUtility::MachineIdent_OS_Mask) !=
(fileMachineIdent & OSUtility::MachineIdent_OS_Mask))
m_Support = ReplaySupport::SuggestRemote;
}
}
}
rdctype::pair<ReplayStatus, IReplayRenderer *> CaptureFile::OpenCapture(float *progress)
{
if(m_Status != ReplayStatus::Succeeded)
return rdctype::make_pair<ReplayStatus, IReplayRenderer *>(m_Status, NULL);
ReplayRenderer *render = new ReplayRenderer();
ReplayStatus ret;
RenderDoc::Inst().SetProgressPtr(progress);
ret = render->CreateDevice(Filename());
RenderDoc::Inst().SetProgressPtr(NULL);
if(ret != ReplayStatus::Succeeded)
SAFE_DELETE(render);
return rdctype::make_pair<ReplayStatus, IReplayRenderer *>(ret, render);
}
rdctype::array<byte> CaptureFile::GetThumbnail(FileType type, uint32_t maxsize)
{
rdctype::array<byte> buf;
Serialiser ser(Filename(), Serialiser::READING, false);
if(ser.HasError())
return buf;
ser.Rewind();
int chunkType = ser.PushContext(NULL, NULL, 1, false);
if(chunkType != THUMBNAIL_DATA)
return buf;
bool HasThumbnail = false;
ser.Serialise(NULL, HasThumbnail);
if(!HasThumbnail)
return buf;
byte *jpgbuf = NULL;
size_t thumblen = 0;
uint32_t thumbwidth = 0, thumbheight = 0;
{
ser.Serialise("ThumbWidth", thumbwidth);
ser.Serialise("ThumbHeight", thumbheight);
ser.SerialiseBuffer("ThumbnailPixels", jpgbuf, thumblen);
}
if(jpgbuf == NULL)
return buf;
// if the desired output is jpg and either there's no max size or it's already satisfied,
// return the data directly
if(type == FileType::JPG && (maxsize == 0 || (maxsize > thumbwidth && maxsize > thumbheight)))
{
create_array_init(buf, thumblen, jpgbuf);
}
else
{
// otherwise we need to decode, resample maybe, and re-encode
int w = (int)thumbwidth;
int h = (int)thumbheight;
int comp = 3;
byte *thumbpixels =
jpgd::decompress_jpeg_image_from_memory(jpgbuf, (int)thumblen, &w, &h, &comp, 3);
if(maxsize != 0)
{
uint32_t clampedWidth = RDCMIN(maxsize, thumbwidth);
uint32_t clampedHeight = RDCMIN(maxsize, thumbheight);
if(clampedWidth != thumbwidth || clampedHeight != thumbheight)
{
// preserve aspect ratio, take the smallest scale factor and multiply both
float scaleX = float(clampedWidth) / float(thumbwidth);
float scaleY = float(clampedHeight) / float(thumbheight);
if(scaleX < scaleY)
clampedHeight = uint32_t(scaleX * thumbheight);
else if(scaleY < scaleX)
clampedWidth = uint32_t(scaleY * thumbwidth);
byte *resizedpixels = (byte *)malloc(3 * clampedWidth * clampedHeight);
stbir_resize_uint8_srgb(thumbpixels, thumbwidth, thumbheight, 0, resizedpixels,
clampedWidth, clampedHeight, 0, 3, -1, 0);
free(thumbpixels);
thumbpixels = resizedpixels;
thumbwidth = clampedWidth;
thumbheight = clampedHeight;
}
}
std::vector<byte> encodedBytes;
switch(type)
{
case FileType::JPG:
{
int len = thumbwidth * thumbheight * 3;
encodedBytes.resize(len);
jpge::params p;
p.m_quality = 90;
jpge::compress_image_to_jpeg_file_in_memory(&encodedBytes[0], len, (int)thumbwidth,
(int)thumbheight, 3, thumbpixels, p);
encodedBytes.resize(len);
break;
}
case FileType::PNG:
{
stbi_write_png_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
3, thumbpixels, 0);
break;
}
case FileType::TGA:
{
stbi_write_tga_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
3, thumbpixels);
break;
}
case FileType::BMP:
{
stbi_write_bmp_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
3, thumbpixels);
break;
}
default:
{
RDCERR("Unsupported file type %d in thumbnail fetch", type);
free(thumbpixels);
delete[] jpgbuf;
return buf;
}
}
buf = encodedBytes;
free(thumbpixels);
}
delete[] jpgbuf;
return buf;
}
extern "C" RENDERDOC_API ICaptureFile *RENDERDOC_CC RENDERDOC_OpenCaptureFile(const char *logfile)
{
return new CaptureFile(logfile);
}
+21 -175
View File
@@ -28,15 +28,10 @@
#include "api/replay/version.h"
#include "common/common.h"
#include "core/core.h"
#include "jpeg-compressor/jpgd.h"
#include "jpeg-compressor/jpge.h"
#include "maths/camera.h"
#include "maths/formatpacking.h"
#include "replay/replay_renderer.h"
#include "serialise/serialiser.h"
#include "replay/type_helpers.h"
#include "serialise/string_utils.h"
#include "stb/stb_image_resize.h"
#include "stb/stb_image_write.h"
// these entry points are for the replay/analysis side - not for the application.
@@ -339,66 +334,39 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_TriggerExceptionHandler(voi
extern "C" RENDERDOC_API ReplaySupport RENDERDOC_CC RENDERDOC_SupportLocalReplay(
const char *logfile, rdctype::str *driver, rdctype::str *recordMachineIdent)
{
if(logfile == NULL)
return ReplaySupport::Unsupported;
RDCDriver driverType = RDC_Unknown;
string driverName = "";
uint64_t fileMachineIdent = 0;
RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, fileMachineIdent, NULL);
ICaptureFile *file = RENDERDOC_OpenCaptureFile(logfile);
if(driver)
*driver = driverName;
*driver = file->DriverName();
bool supported = RenderDoc::Inst().HasReplayDriver(driverType);
if(recordMachineIdent)
*recordMachineIdent = file->RecordedMachineIdent();
if(!supported)
return ReplaySupport::Unsupported;
ReplaySupport support = file->LocalReplaySupport();
if(fileMachineIdent != 0)
{
uint64_t machineIdent = OSUtility::GetMachineIdent();
file->Shutdown();
if(recordMachineIdent)
*recordMachineIdent = OSUtility::MakeMachineIdentString(fileMachineIdent);
if((machineIdent & OSUtility::MachineIdent_OS_Mask) !=
(fileMachineIdent & OSUtility::MachineIdent_OS_Mask))
return ReplaySupport::SuggestRemote;
}
return ReplaySupport::Supported;
return support;
}
extern "C" RENDERDOC_API ReplayStatus RENDERDOC_CC
RENDERDOC_CreateReplayRenderer(const char *logfile, float *progress, IReplayRenderer **rend)
{
if(rend == NULL)
return ReplayStatus::InternalError;
ICaptureFile *file = RENDERDOC_OpenCaptureFile(logfile);
RenderDoc::Inst().SetProgressPtr(progress);
ReplayRenderer *render = new ReplayRenderer();
if(!render)
{
RenderDoc::Inst().SetProgressPtr(NULL);
return ReplayStatus::InternalError;
}
ReplayStatus ret = render->CreateDevice(logfile);
ReplayStatus ret = file->OpenStatus();
if(ret != ReplayStatus::Succeeded)
{
delete render;
RenderDoc::Inst().SetProgressPtr(NULL);
file->Shutdown();
return ret;
}
*rend = render;
std::tie(ret, *rend) = file->OpenCapture(progress);
RenderDoc::Inst().SetProgressPtr(NULL);
return ReplayStatus::Succeeded;
file->Shutdown();
return ret;
}
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC
@@ -429,142 +397,20 @@ RENDERDOC_InjectIntoProcess(uint32_t pid, const rdctype::array<EnvironmentModifi
return Process::InjectIntoProcess(pid, env, logfile, opts, waitForExit != 0);
}
static void writeToByteVector(void *context, void *data, int size)
{
std::vector<byte> *vec = (std::vector<byte> *)context;
byte *start = (byte *)data;
byte *end = start + size;
vec->insert(vec->end(), start, end);
}
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *filename,
FileType type, uint32_t maxsize,
rdctype::array<byte> *buf)
{
Serialiser ser(filename, Serialiser::READING, false);
ICaptureFile *file = RENDERDOC_OpenCaptureFile(filename);
if(ser.HasError())
return false;
ser.Rewind();
int chunkType = ser.PushContext(NULL, NULL, 1, false);
if(chunkType != THUMBNAIL_DATA)
return false;
bool HasThumbnail = false;
ser.Serialise(NULL, HasThumbnail);
if(!HasThumbnail)
return false;
byte *jpgbuf = NULL;
size_t thumblen = 0;
uint32_t thumbwidth = 0, thumbheight = 0;
if(file->OpenStatus() != ReplayStatus::Succeeded)
{
ser.Serialise("ThumbWidth", thumbwidth);
ser.Serialise("ThumbHeight", thumbheight);
ser.SerialiseBuffer("ThumbnailPixels", jpgbuf, thumblen);
file->Shutdown();
return false;
}
if(jpgbuf == NULL)
return false;
// if the desired output is jpg and either there's no max size or it's already satisfied,
// return the data directly
if(type == FileType::JPG && (maxsize == 0 || (maxsize > thumbwidth && maxsize > thumbheight)))
{
create_array_init(*buf, thumblen, jpgbuf);
}
else
{
// otherwise we need to decode, resample maybe, and re-encode
int w = (int)thumbwidth;
int h = (int)thumbheight;
int comp = 3;
byte *thumbpixels =
jpgd::decompress_jpeg_image_from_memory(jpgbuf, (int)thumblen, &w, &h, &comp, 3);
if(maxsize != 0)
{
uint32_t clampedWidth = RDCMIN(maxsize, thumbwidth);
uint32_t clampedHeight = RDCMIN(maxsize, thumbheight);
if(clampedWidth != thumbwidth || clampedHeight != thumbheight)
{
// preserve aspect ratio, take the smallest scale factor and multiply both
float scaleX = float(clampedWidth) / float(thumbwidth);
float scaleY = float(clampedHeight) / float(thumbheight);
if(scaleX < scaleY)
clampedHeight = uint32_t(scaleX * thumbheight);
else if(scaleY < scaleX)
clampedWidth = uint32_t(scaleY * thumbwidth);
byte *resizedpixels = (byte *)malloc(3 * clampedWidth * clampedHeight);
stbir_resize_uint8_srgb(thumbpixels, thumbwidth, thumbheight, 0, resizedpixels,
clampedWidth, clampedHeight, 0, 3, -1, 0);
free(thumbpixels);
thumbpixels = resizedpixels;
thumbwidth = clampedWidth;
thumbheight = clampedHeight;
}
}
std::vector<byte> encodedBytes;
switch(type)
{
case FileType::JPG:
{
int len = thumbwidth * thumbheight * 3;
encodedBytes.resize(len);
jpge::params p;
p.m_quality = 90;
jpge::compress_image_to_jpeg_file_in_memory(&encodedBytes[0], len, (int)thumbwidth,
(int)thumbheight, 3, thumbpixels, p);
encodedBytes.resize(len);
break;
}
case FileType::PNG:
{
stbi_write_png_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
3, thumbpixels, 0);
break;
}
case FileType::TGA:
{
stbi_write_tga_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
3, thumbpixels);
break;
}
case FileType::BMP:
{
stbi_write_bmp_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
3, thumbpixels);
break;
}
default:
{
RDCERR("Unsupported file type %d in thumbnail fetch", type);
free(thumbpixels);
delete[] jpgbuf;
return false;
}
}
*buf = encodedBytes;
free(thumbpixels);
}
delete[] jpgbuf;
*buf = file->GetThumbnail(type, maxsize);
file->Shutdown();
return true;
}
+25 -5
View File
@@ -252,10 +252,19 @@ struct ThumbCommand : public Command
}
rdctype::array<byte> buf;
bool32 ret =
RENDERDOC_GetThumbnail(filename.c_str(), type, parser.get<uint32_t>("max-size"), &buf);
if(!ret)
ICaptureFile *file = RENDERDOC_OpenCaptureFile(filename.c_str());
if(file->OpenStatus() == ReplayStatus::Succeeded)
{
buf = file->GetThumbnail(FileType::JPG, 0);
}
else
{
std::cerr << "Couldn't open '" << filename << "'" << std::endl;
}
file->Shutdown();
if(buf.empty())
{
std::cerr << "Couldn't fetch the thumbnail in '" << filename << "'" << std::endl;
}
@@ -522,9 +531,19 @@ struct ReplayCommand : public Command
{
std::cout << "Replaying '" << filename << "' locally.." << std::endl;
float progress = 0.0f;
ICaptureFile *file = RENDERDOC_OpenCaptureFile(filename.c_str());
if(file->OpenStatus() != ReplayStatus::Succeeded)
{
std::cerr << "Couldn't load '" << filename << "'." << std::endl;
return 1;
}
IReplayRenderer *renderer = NULL;
ReplayStatus status = RENDERDOC_CreateReplayRenderer(filename.c_str(), &progress, &renderer);
ReplayStatus status = ReplayStatus::InternalError;
std::tie(status, renderer) = file->OpenCapture(NULL);
file->Shutdown();
if(status == ReplayStatus::Succeeded)
{
@@ -536,6 +555,7 @@ struct ReplayCommand : public Command
else
{
std::cerr << "Couldn't load and replay '" << filename << "'." << std::endl;
return 1;
}
}
return 0;