mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-06 23:00:59 +00:00
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:
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.";
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user