Cogs.Core
ReadbackTask.cpp
1#include "ReadbackTask.h"
2
3#include "Rendering/IGraphicsDevice.h"
4#include "Rendering/IContext.h"
5
6#include "Foundation/Logging/Logger.h"
7
8#include "Services/Time.h"
9
10#include "Renderer/RenderBuffer.h"
11#include "Renderer/RenderList.h"
12#include "Renderer/RenderTarget.h"
13
14#include "Context.h"
15
16namespace
17{
18 Cogs::Logging::Log logger = Cogs::Logging::getLogger("ReadbackTask");
19}
20
21void Cogs::Core::ReadbackTask::apply(RenderTaskContext * renderContext)
22{
23 RenderInstrumentationScope(renderContext->device->getImmediateContext(), SCOPE_RENDERING, "ReadbackTask::apply");
24
25 auto device = renderContext->device;
26 auto deviceContext = device->getImmediateContext();
27
28 if (size > std::numeric_limits<uint32_t>::max()) {
29 LOG_ERROR(logger, "Invalid readback size %zd.", size.getValue());
30 return;
31 }
32
33 auto source = input.get(RenderResourceType::RenderBuffer);
34
35 if (!source) {
36 LOG_ERROR(logger, "No input resource bound for readback.");
37 return;
38 }
39
40 auto inputBuffer = source->renderBuffer;
41
42 if (size > inputBuffer->size) {
43 LOG_ERROR(logger, "Readback size (%zd) larger than buffer size %zd.", size.getValue(), inputBuffer->size);
44 return;
45 }
46
47 if (size % inputBuffer->elementSize != 0) {
48 LOG_WARNING(logger, "Readback size %zd not multiple of input element size %zd.", size.getValue(), inputBuffer->elementSize.getValue());
49 }
50
51 auto bufferHandle = inputBuffer->getHandle(bufferIndex);
52
53 if (!HandleIsValid(bufferHandle)) {
54 LOG_ERROR(logger, "Invalid buffer handle for buffer: %.*s, index: %zd.", StringViewFormat(inputBuffer->getName()), bufferIndex.getValue());
55 return;
56 }
57
58 auto mappedData = deviceContext->map(bufferHandle, MapMode::Read);
59
60 if (!mappedData) {
61 LOG_ERROR(logger, "Could not map resource for readback.");
62 return;
63 }
64
65 hostBuffer.resize(size, false);
66 std::memcpy(hostBuffer.data(), mappedData, size);
67 deviceContext->unmap(bufferHandle);
68 uint32_t frame = inputBuffer->getFrame(bufferIndex);
69
70 bool published = false;
71 const auto * list = input.get(RenderResourceType::RenderList);
72 for (auto it : renderContext->context->callbacks.readbackCallbackInternal) {
73 (*it)(renderContext->context, list ? list->renderList->viewportData : nullptr, frame, key.data(), hostBuffer.data(), (int)hostBuffer.size());
74 published = true;
75 }
76
77 if (renderContext->context->callbacks.readbackCallback) {
78 renderContext->context->callbacks.readbackCallback(renderContext->context, key.data(), hostBuffer.data(), (int)hostBuffer.size());
79 published = true;
80 }
81
82 if (published) {
83 errorState = false;
84 }
85 else if (!errorState) {
86 LOG_WARNING(logger, "Performed readback of %.*s without callback.", StringViewFormat(inputBuffer->getName()));
87 errorState = true;
88 }
89}
Log implementation class.
Definition: LogManager.h:139
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180