1#include "RenderListTask.h"
2#include "GenerateListTask.h"
3#include "FilterListTask.h"
5#include "Renderer/Renderer.h"
6#include "Renderer/RenderTexture.h"
7#include "Renderer/RenderMaterialInstance.h"
8#include "Renderer/RenderResources.h"
9#include "Renderer/RenderStateUpdater.h"
10#include "Renderer/RenderTexture.h"
11#include "Renderer/RenderTarget.h"
12#include "Renderer/EnginePermutations.h"
14#include "Platform/Instrumentation.h"
18#include "Services/Time.h"
19#include "Services/Variables.h"
21#include "Rendering/ITextures.h"
22#include "Rendering/IRenderTargets.h"
23#include "Rendering/ICapabilities.h"
25#include "Foundation/Logging/Logger.h"
26#include "Foundation/Collections/SmallVector.h"
29#include <glm/gtc/color_space.hpp>
38Cogs::Core::RenderListTask::RenderListTask()
42Cogs::Core::RenderListTask::~RenderListTask()
46void Cogs::Core::RenderListTask::initialize(RenderTaskContext * context)
48 RenderTask::initialize(context);
50 auto renderTargets = context->device->getRenderTargets();
52 blendState = renderTargets->loadBlendState(&context->states->blendStates[
size_t(blendMode)].color,
53 &context->states->blendStates[
size_t(blendMode)].alpha, 1, BlendFlags::IndependentBlend);
54 depthState = context->states->commonDepthStates[(int)DepthMode::Count*(
int)depthFunc+(int)depthMode];
56 scopeName = context->renderer->getEnginePermutations().get(permutationIndex)->getName();
59void Cogs::Core::RenderListTask::apply(RenderTaskContext * context)
61 DynamicRenderInstrumentationScope(context->device->getImmediateContext(), SCOPE_RENDERING,
"RenderListTask", scopeName.c_str());
63 if (!validate(context, 1, 1))
return;
65 const auto renderList = input.get(RenderResourceType::RenderList)->renderList;
66 auto renderTarget = output.get(RenderResourceType::RenderTarget)->renderTarget;
69 LOG_ERROR(logger,
"Missing input render list for %s.", scopeName.c_str());
74 LOG_ERROR(logger,
"Missing output target for %s.", scopeName.c_str());
79 if (renderList->hash == lastHash)
return;
80 lastHash = renderList->hash;
83 if (renderList->viewportData->viewportSize.x == 0 || renderList->viewportData->viewportSize.y == 0)
return;
85 auto deviceContext = context->device->getImmediateContext();
87 setupRenderTarget(context, renderTarget, renderList->viewportData);
89 updateEngineBuffers(context, renderTarget, renderList->viewportData,
nullptr);
97 if (context->device->getCapabilities()->getDeviceCapabilities().RenderPass &&
98 !renderList->viewportData->bindRenderTargetCallback) {
99 deviceContext->endRenderPass();
102 for (
auto t : renderTarget->textures) {
104 context->device->getTextures()->generateMipmaps(t->textureHandle);
109bool Cogs::Core::RenderListTask::validate(RenderTaskContext * ,
size_t expectedInputs,
size_t expectedOutputs)
111 const bool validInputs = input.resources.size() >= expectedInputs;
112 const bool validOutputs = output.resources.size() >= expectedOutputs;
114 if (validInputs && validOutputs) {
117 LOG_ERROR(logger,
"Failed validating connections for %s.", scopeName.c_str());
122void Cogs::Core::RenderListTask::applyMaterial(
const DrawContext & drawContext,
const RenderItem & item)
124 updateEnvironmentBindings(&drawContext, item.binding);
126 auto permutation = drawContext.permutation;
128 for (
auto & buffer : drawContext.permutation->constantBuffers.buffers) {
129 permutation->bufferHandles.resize(permutation->constantBuffers.buffers.size());
131 if (!
HandleIsValid(permutation->bufferHandles[buffer.index])) {
132 IBuffers* buffers = drawContext.device->getBuffers();
134 buffers->annotate(permutation->bufferHandles[buffer.index],
"RenderListTask::applyMaterial");
137 drawContext.deviceContext->updateBuffer(permutation->bufferHandles[buffer.index], buffer.content.data(), buffer.size);
138 drawContext.deviceContext->setConstantBuffer(buffer.name, permutation->bufferHandles[buffer.index]);
142void Cogs::Core::RenderListTask::renderBatched(RenderTaskContext * taskContext,
143 DrawContext & drawContext,
144 const RenderList* renderList,
145 const RenderItems & items,
147 StateChangeFlags stateChangeMask,
150 auto renderer = taskContext->renderer;
151 auto device = renderer->getDevice();
153 auto context = device->getImmediateContext();
155 auto setViewport = [&](
const CameraData & c) {
156 context->setViewport(
159 (!viewportFromTarget && (c.viewportSize.x != 0)) ? c.viewportSize.x :
static_cast<float>(defaultViewportSize.x),
160 (!viewportFromTarget && (c.viewportSize.y != 0)) ? c.viewportSize.y :
static_cast<float>(defaultViewportSize.y));
164 size_t n = items.size();
167 size_t m = batched ? populateObjectBuffer(&drawContext, items.data(), o, n) : o + 1;
169 for (
size_t i = o; i < m; i++) {
170 const RenderItem & currentItem = items[i];
172 if (currentItem.isCustom1()) {
173 (*currentItem.callback)(taskContext, &drawContext, ¤tItem);
176 if (currentItem.isCustom2()) {
177 (*currentItem.callback2)(taskContext, &drawContext,
this, ¤tItem);
181 const StateChangeFlags stateChanges = currentItem.stateChanges & stateChangeMask;
183 if ((stateChanges & StateChangeFlags::ChangeViewport) != 0) {
184 setViewport(*drawContext.cameraData);
187 if ((stateChanges & StateChangeFlags::ChangeDepthStencilState) != 0) {
188 context->setDepthStencilState(taskContext->states->commonDepthStates[currentItem.depthState]);
191 if ((stateChanges & StateChangeFlags::ChangeBlendState) != 0) {
192 context->setBlendState(taskContext->states->blendStates[currentItem.blendState].handle);
195 if ((stateChanges & StateChangeFlags::ChangeRasterizerState) != 0) {
196 context->setRasterizerState(taskContext->states->rasterizerStateHandles[currentItem.rasterizerState]);
199 if ((stateChanges & StateChangeFlags::ChangeViewportData) != 0) {
200 const ClipShapeCache::Item& clipShape = renderList->clipShapeCache->data[currentItem.clipShapeIx];
201 updateViewportBuffer(taskContext, taskContext->engineBuffers->sceneBufferHandle, taskContext->engineBuffers->viewBufferHandle, drawContext.renderTarget, currentItem.viewportData ? currentItem.viewportData : drawContext.cameraData, &clipShape.clipEquations);
204 if ((stateChanges & StateChangeFlags::ChangeMaterialVariant) != 0) {
205 applyMaterialPermutation(taskContext, &drawContext, currentItem.binding, currentItem.renderMaterialInstance);
207 applyMaterial(drawContext, currentItem);
210 if ((stateChanges & StateChangeFlags::ChangeMaterialInstance) != 0) {
211 applyMaterialInstance(&drawContext, currentItem.binding, currentItem.renderMaterialInstance);
214 if ((stateChanges & StateChangeFlags::ChangeMesh) != 0) {
217 context->setVertexArrayObject(currentItem.vertexArrayObject);
220 context->setVertexBuffers(currentItem.meshData->vertexBuffers, currentItem.meshData->streamsLayout.numStreams, currentItem.meshData->vertexStrides, currentItem.meshData->vertexOffsets);
223 context->setIndexBuffer(currentItem.meshData->indexBuffer, currentItem.meshData->indexStride, currentItem.meshData->indexOffset);
229 applyMaterialPerObjectBatched(&drawContext, currentItem.renderMaterialInstance, currentItem, i - o);
232 applyMaterialPerObject(&drawContext, currentItem.renderMaterialInstance, currentItem);
235 if (currentItem.isInstanced()) {
237 if (currentItem.instanceData) {
238 auto renderMesh = currentItem.meshData;
239 auto instanceMesh = currentItem.instanceData;
241 assert(renderMesh && instanceMesh &&
"Invalid instanced rendering data.");
242 assert(renderMesh->streamsLayout.numStreams && instanceMesh->streamsLayout.numStreams &&
"Missing instanced render buffers.");
250 size_t numStreams = 0;
251 for (
size_t j = 0; j < renderMesh->streamsLayout.numStreams; j++) {
252 vertexBuffers[numStreams] = renderMesh->vertexBuffers[j];
253 strides[numStreams] = renderMesh->vertexStrides[j];
254 offsets[numStreams] = renderMesh->vertexOffsets[j];
259 for (
size_t j = 0; j < instanceMesh->streamsLayout.numStreams; j++) {
260 vertexBuffers[numStreams] = instanceMesh->vertexBuffers[j];
261 strides[numStreams] = instanceMesh->vertexStrides[j];
262 offsets[numStreams] = instanceMesh->vertexOffsets[j];
266 context->setVertexBuffers(vertexBuffers, numStreams, strides, offsets);
269 if (currentItem.meshData->indexBuffer) {
270 context->setIndexBuffer(currentItem.meshData->indexBuffer);
271 context->drawInstancedIndexed(currentItem.primitiveType, currentItem.startInstance, currentItem.numInstances, currentItem.startIndex, currentItem.numIndexes);
273 context->drawInstanced(currentItem.primitiveType, currentItem.startIndex, currentItem.numIndexes, currentItem.startInstance, currentItem.numInstances);
278 context->drawIndexed(currentItem.primitiveType, currentItem.startIndex, currentItem.numIndexes);
280 context->draw(currentItem.primitiveType, currentItem.startIndex, currentItem.numIndexes);
291void Cogs::Core::RenderListTask::setupRenderTarget(RenderTaskContext * context, RenderTarget * renderTarget,
const CameraData * viewportData)
293 defaultViewportSize.x = renderTarget->width;
294 defaultViewportSize.y = renderTarget->height;
296 auto deviceContext = context->device->getImmediateContext();
298 const RenderSettings& renderSettings = context->renderer->getSettings();
299 MaterialOptions defaultMaterialOptions;
300 RenderPassOptions defaultPassOptions;
302 const bool isBackBuffer =
305 const bool doScissor = viewportData->passOptions &&
306 viewportData->passOptions->getFlag(RenderPassOptions::Flags::ScissorTest);
307 bool doColorClear = colorClear &&
309 bool doDepthClear = depthClear &&
310 (
HandleIsValid(renderTarget->depthTargetHandle) || isBackBuffer);
311 if (isBackBuffer && (renderSettings.defaultRenderTargetClear ==
false)) {
312 doColorClear =
false;
313 doDepthClear =
false;
315 bool isCleared =
false;
317 size_t nt = renderTarget->textures.size();
318 size_t no = std::max(
size_t(1), nt);
319 glm::vec4 clearColorSRGB;
320 Collections::SmallVector<const float*, 8> clearColors(no);
322 glm::vec4 black(0.f);
324 size_t nc = renderTarget->clearColors.size();
326 for (
size_t i = 0; i < no; i++) {
328 clearColors[i] = i == 0 ? glm::value_ptr(viewportData->useClearColor ? viewportData->clearColor : context->renderer->getBackgroundColor()) : glm::value_ptr(black);
330 if (i < nt && renderTarget->textures[i]->clearColorSet) {
331 clearColors[i] = renderTarget->textures[i]->clearColor;
335 clearColors[i] = glm::value_ptr(renderTarget->clearColors[i]);
340 if ((isBackBuffer && renderSettings.defaultRenderTargetExpectsSRGB) || renderTarget->expectsSRGB) {
341 clearColorSRGB = glm::vec4(glm::convertLinearToSRGB(glm::make_vec3(clearColors[0])), clearColors[0][3]);
342 clearColors[0] = glm::value_ptr(clearColorSRGB);
347 if (viewportData->bindRenderTargetCallback) {
348 viewportData->bindRenderTargetCallback(viewportData->bindRenderTargetCallbackData);
351 if(context->device->getCapabilities()->getDeviceCapabilities().RenderPass){
353 info.renderTargetHandle = renderTarget->renderTargetHandle;
354 info.depthStencilHandle = renderTarget->depthTargetHandle;
355 for (
size_t i = 0; i < no; i++) {
356 info.loadOp[i] = doColorClear ? LoadOp::Clear : LoadOp::Load;
357 info.storeOp[i] = discardColor ? StoreOp::Discard : StoreOp::Store;
358 info.clearValue[i][0] = clearColors[i][0];
359 info.clearValue[i][1] = clearColors[i][1];
360 info.clearValue[i][2] = clearColors[i][2];
361 info.clearValue[i][3] = clearColors[i][3];
363 info.depthLoadOp = doDepthClear ? LoadOp::Clear : LoadOp::Load;
364 info.depthStoreOp = discardDepth ? StoreOp::Discard : StoreOp::Store;
365 info.depthClearValue = context->renderer->getClearDepth();
366 info.depthReadOnly = !depthWrite;
367 deviceContext->beginRenderPass(info);
371 deviceContext->setRenderTarget(renderTarget->renderTargetHandle, renderTarget->depthTargetHandle);
375 if (doScissor || doColorClear || doDepthClear || viewportData->bindRenderTargetCallback) {
378 uint16_t rasterizerStateIx = context->states->getRasterizerState(viewportData->passOptions ? *viewportData->passOptions : defaultPassOptions,
382 RasterizerStateHandle& rasterizerStateHandle = context->states->rasterizerStateHandles[rasterizerStateIx];
383 deviceContext->setRasterizerState(rasterizerStateHandle);
387 auto & rect = viewportData->passOptions->scissorRectangle;
388 deviceContext->setScissor(rect.x, rect.y, rect.z, rect.w);
391 if(!context->device->getCapabilities()->getDeviceCapabilities().RenderPass){
392 if (doColorClear && !isCleared) {
394 deviceContext->clearRenderTarget(clearColors[0]);
397 deviceContext->clearRenderTarget((
const float**)clearColors.data(),
static_cast<int>(nt));
401 if (doDepthClear && !isCleared) {
402 deviceContext->clearDepth(context->renderer->getClearDepth());
406 deviceContext->setBlendState(blendState);
407 deviceContext->setDepthStencilState(depthState);
410void Cogs::Core::RenderListTask::renderItems(RenderTaskContext * taskContext,
411 RenderTarget* renderTarget,
412 const RenderList* renderList,
413 BucketMask bucketMask,
414 StateChangeFlags stateChangeMask)
416 auto renderer = taskContext->renderer;
417 auto device = taskContext->device;
420 std::sprintf(buffer,
"mask=0x%08X",
static_cast<int>(bucketMask));
421 DynamicRenderInstrumentationScope(taskContext->device->getImmediateContext(), SCOPE_RENDERING,
"RenderListTask::renderItems", buffer);
423 auto enginePermutation = renderer->getEnginePermutations().get(permutationIndex);
426 uint32_t frame = taskContext->context->time->getFrame();
427 uint32_t widthDivisor = taskContext->context->variables->get(
"renderer.oit.TemporalUpscaleWidth", 1);
428 uint32_t heightDivisor = taskContext->context->variables->get(
"renderer.oit.TemporalUpscaleHeight", 1);
429 uint32_t i = frame % (widthDivisor * heightDivisor);
430 uint32_t w = i%widthDivisor;
431 uint32_t h = (i/widthDivisor)%heightDivisor;
433 CameraData &viewportData(*(CameraData*)renderList->viewportData);
434 viewportData.projectionMatrix = taskContext->renderer->getProjectionMatrix(viewportData.rawProjectionMatrix);
435 viewportData.projectionMatrix[2][0] += (float)w*(2.0f/widthDivisor)/(float)renderTarget->width;
436 viewportData.projectionMatrix[2][1] -= (
float)h*(2.0f/heightDivisor)/(
float)renderTarget->height;
437 viewportData.viewProjection = viewportData.projectionMatrix * viewportData.viewMatrix;
438 viewportData.inverseViewProjectionMatrix = glm::inverse(viewportData.viewProjection);
439 viewportData.inverseProjectionMatrix = glm::inverse(viewportData.projectionMatrix);
442 DrawContext drawContext;
443 drawContext.context = taskContext->context;
444 drawContext.renderer = renderer;
445 drawContext.device = device;
446 drawContext.deviceContext = device->getImmediateContext();
447 drawContext.cameraData = renderList->viewportData;
448 drawContext.permutationIndex = enginePermutation->getIndex();
449 drawContext.permutation = enginePermutation;
450 drawContext.engineBuffers = &renderer->getEngineBuffers();
451 drawContext.renderTarget = renderTarget;
452 drawContext.taskContext = taskContext;
453 drawContext.task =
this;
454 drawContext.listObjectBuffer = renderList->listObjectBuffer;
455 drawContext.clipShapeCache = renderList->clipShapeCache;
457 bool batchObjectBuffer = drawContext.engineBuffers->objectBatch.count != 0;
458 const StringView batchObjectBufferKey =
"renderer.batchObjectBuffer";
459 if (Variable* var = drawContext.context->variables->get(batchObjectBufferKey); !var->isEmpty()) {
460 batchObjectBuffer = var->getBool();
463 drawContext.context->variables->set(batchObjectBufferKey, batchObjectBuffer);
467 if (drawContext.listObjectBuffer && drawContext.listObjectBuffer->isInUse()) {
468 objectBufferMode = ObjectBufferMode::List;
469 batchObjectBuffer =
false;
471 else if (drawContext.engineBuffers->objectBatch.count && batchObjectBuffer) {
472 objectBufferMode = ObjectBufferMode::Batched;
475 objectBufferMode = ObjectBufferMode::Single;
476 batchObjectBuffer =
false;
479 for (
size_t b = 0; b < size_t(BucketType::Count); b++) {
480 if ((BucketMask(1 << b) & bucketMask) == 0)
continue;
482 const RenderItems & items = renderList->buckets[b];
483 renderBatched(taskContext, drawContext, renderList, items, bucketMask, stateChangeMask, batchObjectBuffer);
487 CameraData &viewportData(*(CameraData*)renderList->viewportData);
488 viewportData.projectionMatrix = taskContext->renderer->getProjectionMatrix(viewportData.rawProjectionMatrix);
489 viewportData.viewProjection = viewportData.projectionMatrix * viewportData.viewMatrix;
490 viewportData.inverseViewProjectionMatrix = glm::inverse(viewportData.viewProjection);
491 viewportData.inverseProjectionMatrix = glm::inverse(viewportData.projectionMatrix);
Log implementation class.
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
@ Write
The buffer can be mapped and written to by the CPU after creation.
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
static constexpr size_t maxStreams
static const Handle_t NoHandle
Represents a handle to nothing.
@ Back
Cull back facing primitives.
@ GenerateMipMaps
The texture supports automatic mipmap generation performed by the graphics device.
@ Dynamic
Buffer will be loaded and modified with some frequency.