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 auto deviceContext = context->device->getImmediateContext();
85 setupRenderTarget(context, renderTarget, renderList->viewportData);
87 updateEngineBuffers(context, renderTarget, renderList->viewportData,
nullptr);
95 if (context->device->getCapabilities()->getDeviceCapabilities().RenderPass &&
96 !renderList->viewportData->bindRenderTargetCallback) {
97 deviceContext->endRenderPass();
100 for (
auto t : renderTarget->textures) {
102 context->device->getTextures()->generateMipmaps(t->textureHandle);
107bool Cogs::Core::RenderListTask::validate(RenderTaskContext * ,
size_t expectedInputs,
size_t expectedOutputs)
109 const bool validInputs = input.resources.size() >= expectedInputs;
110 const bool validOutputs = output.resources.size() >= expectedOutputs;
112 if (validInputs && validOutputs) {
115 LOG_ERROR(logger,
"Failed validating connections for %s.", scopeName.c_str());
120void Cogs::Core::RenderListTask::applyMaterial(
const DrawContext & drawContext,
const RenderItem & item)
122 updateEnvironmentBindings(&drawContext, item.binding);
124 auto permutation = drawContext.permutation;
126 for (
auto & buffer : drawContext.permutation->constantBuffers.buffers) {
127 permutation->bufferHandles.resize(permutation->constantBuffers.buffers.size());
129 if (!
HandleIsValid(permutation->bufferHandles[buffer.index])) {
130 IBuffers* buffers = drawContext.device->getBuffers();
132 buffers->annotate(permutation->bufferHandles[buffer.index],
"RenderListTask::applyMaterial");
135 drawContext.deviceContext->updateBuffer(permutation->bufferHandles[buffer.index], buffer.content.data(), buffer.size);
136 drawContext.deviceContext->setConstantBuffer(buffer.name, permutation->bufferHandles[buffer.index]);
140void Cogs::Core::RenderListTask::renderBatched(RenderTaskContext * taskContext,
141 DrawContext & drawContext,
142 const RenderList* renderList,
143 const RenderItems & items,
145 StateChangeFlags stateChangeMask,
148 auto renderer = taskContext->renderer;
149 auto device = renderer->getDevice();
151 auto context = device->getImmediateContext();
153 auto setViewport = [&](
const CameraData & c) {
154 context->setViewport(
157 (!viewportFromTarget && (c.viewportSize.x != 0)) ? c.viewportSize.x :
static_cast<float>(defaultViewportSize.x),
158 (!viewportFromTarget && (c.viewportSize.y != 0)) ? c.viewportSize.y :
static_cast<float>(defaultViewportSize.y));
162 size_t n = items.size();
165 size_t m = batched ? populateObjectBuffer(&drawContext, items.data(), o, n) : o + 1;
167 for (
size_t i = o; i < m; i++) {
168 const RenderItem & currentItem = items[i];
170 if (currentItem.isCustom1()) {
171 (*currentItem.callback)(taskContext, &drawContext, ¤tItem);
174 if (currentItem.isCustom2()) {
175 (*currentItem.callback2)(taskContext, &drawContext,
this, ¤tItem);
179 const StateChangeFlags stateChanges = currentItem.stateChanges & stateChangeMask;
181 if ((stateChanges & StateChangeFlags::ChangeViewport) != 0) {
182 setViewport(*drawContext.cameraData);
185 if ((stateChanges & StateChangeFlags::ChangeDepthStencilState) != 0) {
186 context->setDepthStencilState(taskContext->states->commonDepthStates[currentItem.depthState]);
189 if ((stateChanges & StateChangeFlags::ChangeBlendState) != 0) {
190 context->setBlendState(taskContext->states->blendStates[currentItem.blendState].handle);
193 if ((stateChanges & StateChangeFlags::ChangeRasterizerState) != 0) {
194 context->setRasterizerState(taskContext->states->rasterizerStateHandles[currentItem.rasterizerState]);
197 if ((stateChanges & StateChangeFlags::ChangeViewportData) != 0) {
198 const ClipShapeCache::Item& clipShape = renderList->clipShapeCache->data[currentItem.clipShapeIx];
199 updateViewportBuffer(taskContext, taskContext->engineBuffers->sceneBufferHandle, taskContext->engineBuffers->viewBufferHandle, drawContext.renderTarget, currentItem.viewportData ? currentItem.viewportData : drawContext.cameraData, &clipShape.clipEquations);
202 if ((stateChanges & StateChangeFlags::ChangeMaterialVariant) != 0) {
203 applyMaterialPermutation(taskContext, &drawContext, currentItem.binding, currentItem.renderMaterialInstance);
205 applyMaterial(drawContext, currentItem);
208 if ((stateChanges & StateChangeFlags::ChangeMaterialInstance) != 0) {
209 applyMaterialInstance(&drawContext, currentItem.binding, currentItem.renderMaterialInstance);
212 if ((stateChanges & StateChangeFlags::ChangeMesh) != 0) {
215 context->setVertexArrayObject(currentItem.vertexArrayObject);
218 context->setVertexBuffers(currentItem.meshData->vertexBuffers, currentItem.meshData->streamsLayout.numStreams, currentItem.meshData->vertexStrides, currentItem.meshData->vertexOffsets);
221 context->setIndexBuffer(currentItem.meshData->indexBuffer, currentItem.meshData->indexStride, currentItem.meshData->indexOffset);
227 applyMaterialPerObjectBatched(&drawContext, currentItem.renderMaterialInstance, currentItem, i - o);
230 applyMaterialPerObject(&drawContext, currentItem.renderMaterialInstance, currentItem);
233 if (currentItem.isInstanced()) {
235 if (currentItem.instanceData) {
236 auto renderMesh = currentItem.meshData;
237 auto instanceMesh = currentItem.instanceData;
239 assert(renderMesh && instanceMesh &&
"Invalid instanced rendering data.");
240 assert(renderMesh->streamsLayout.numStreams && instanceMesh->streamsLayout.numStreams &&
"Missing instanced render buffers.");
248 size_t numStreams = 0;
249 for (
size_t j = 0; j < renderMesh->streamsLayout.numStreams; j++) {
250 vertexBuffers[numStreams] = renderMesh->vertexBuffers[j];
251 strides[numStreams] = renderMesh->vertexStrides[j];
252 offsets[numStreams] = renderMesh->vertexOffsets[j];
257 for (
size_t j = 0; j < instanceMesh->streamsLayout.numStreams; j++) {
258 vertexBuffers[numStreams] = instanceMesh->vertexBuffers[j];
259 strides[numStreams] = instanceMesh->vertexStrides[j];
260 offsets[numStreams] = instanceMesh->vertexOffsets[j];
264 context->setVertexBuffers(vertexBuffers, numStreams, strides, offsets);
267 if (currentItem.meshData->indexBuffer) {
268 context->setIndexBuffer(currentItem.meshData->indexBuffer);
269 context->drawInstancedIndexed(currentItem.primitiveType, currentItem.startInstance, currentItem.numInstances, currentItem.startIndex, currentItem.numIndexes);
271 context->drawInstanced(currentItem.primitiveType, currentItem.startIndex, currentItem.numIndexes, currentItem.startInstance, currentItem.numInstances);
276 context->drawIndexed(currentItem.primitiveType, currentItem.startIndex, currentItem.numIndexes);
278 context->draw(currentItem.primitiveType, currentItem.startIndex, currentItem.numIndexes);
289void Cogs::Core::RenderListTask::setupRenderTarget(RenderTaskContext * context, RenderTarget * renderTarget,
const CameraData * viewportData)
291 defaultViewportSize.x = renderTarget->width;
292 defaultViewportSize.y = renderTarget->height;
294 auto deviceContext = context->device->getImmediateContext();
296 const RenderSettings& renderSettings = context->renderer->getSettings();
297 MaterialOptions defaultMaterialOptions;
298 RenderPassOptions defaultPassOptions;
300 const bool isBackBuffer =
303 const bool doScissor = viewportData->passOptions &&
304 viewportData->passOptions->getFlag(RenderPassOptions::Flags::ScissorTest);
305 bool doColorClear = colorClear &&
307 bool doDepthClear = depthClear &&
308 (
HandleIsValid(renderTarget->depthTargetHandle) || isBackBuffer);
309 if (isBackBuffer && (renderSettings.defaultRenderTargetClear ==
false)) {
310 doColorClear =
false;
311 doDepthClear =
false;
313 bool isCleared =
false;
315 size_t nt = renderTarget->textures.size();
316 size_t no = std::max(
size_t(1), nt);
317 glm::vec4 clearColorSRGB;
318 Collections::SmallVector<const float*, 8> clearColors(no);
320 glm::vec4 black(0.f);
322 size_t nc = renderTarget->clearColors.size();
324 for (
size_t i = 0; i < no; i++) {
326 clearColors[i] = i == 0 ? glm::value_ptr(viewportData->useClearColor ? viewportData->clearColor : context->renderer->getBackgroundColor()) : glm::value_ptr(black);
328 if (i < nt && renderTarget->textures[i]->clearColorSet) {
329 clearColors[i] = renderTarget->textures[i]->clearColor;
333 clearColors[i] = glm::value_ptr(renderTarget->clearColors[i]);
338 if ((isBackBuffer && renderSettings.defaultRenderTargetExpectsSRGB) || renderTarget->expectsSRGB) {
339 clearColorSRGB = glm::vec4(glm::convertLinearToSRGB(glm::make_vec3(clearColors[0])), clearColors[0][3]);
340 clearColors[0] = glm::value_ptr(clearColorSRGB);
345 if (viewportData->bindRenderTargetCallback) {
346 viewportData->bindRenderTargetCallback(viewportData->bindRenderTargetCallbackData);
349 if(context->device->getCapabilities()->getDeviceCapabilities().RenderPass){
351 info.renderTargetHandle = renderTarget->renderTargetHandle;
352 info.depthStencilHandle = renderTarget->depthTargetHandle;
353 for (
size_t i = 0; i < no; i++) {
354 info.loadOp[i] = doColorClear ? LoadOp::Clear : LoadOp::Load;
355 info.storeOp[i] = discardColor ? StoreOp::Discard : StoreOp::Store;
356 info.clearValue[i][0] = clearColors[i][0];
357 info.clearValue[i][1] = clearColors[i][1];
358 info.clearValue[i][2] = clearColors[i][2];
359 info.clearValue[i][3] = clearColors[i][3];
361 info.depthLoadOp = doDepthClear ? LoadOp::Clear : LoadOp::Load;
362 info.depthStoreOp = discardDepth ? StoreOp::Discard : StoreOp::Store;
363 info.depthClearValue = context->renderer->getClearDepth();
364 info.depthReadOnly = !depthWrite;
365 deviceContext->beginRenderPass(info);
369 deviceContext->setRenderTarget(renderTarget->renderTargetHandle, renderTarget->depthTargetHandle);
373 if (doScissor || doColorClear || doDepthClear || viewportData->bindRenderTargetCallback) {
376 uint16_t rasterizerStateIx = context->states->getRasterizerState(viewportData->passOptions ? *viewportData->passOptions : defaultPassOptions,
380 RasterizerStateHandle& rasterizerStateHandle = context->states->rasterizerStateHandles[rasterizerStateIx];
381 deviceContext->setRasterizerState(rasterizerStateHandle);
385 auto & rect = viewportData->passOptions->scissorRectangle;
386 deviceContext->setScissor(rect.x, rect.y, rect.z, rect.w);
389 if (doColorClear && !isCleared) {
391 deviceContext->clearRenderTarget(clearColors[0]);
394 deviceContext->clearRenderTarget((
const float**)clearColors.data(),
static_cast<int>(nt));
398 if (doDepthClear && !isCleared) {
399 deviceContext->clearDepth(context->renderer->getClearDepth());
402 deviceContext->setBlendState(blendState);
403 deviceContext->setDepthStencilState(depthState);
406void Cogs::Core::RenderListTask::renderItems(RenderTaskContext * taskContext,
407 RenderTarget* renderTarget,
408 const RenderList* renderList,
409 BucketMask bucketMask,
410 StateChangeFlags stateChangeMask)
412 auto renderer = taskContext->renderer;
413 auto device = taskContext->device;
416 std::sprintf(buffer,
"mask=0x%08X",
static_cast<int>(bucketMask));
417 DynamicRenderInstrumentationScope(taskContext->device->getImmediateContext(), SCOPE_RENDERING,
"RenderListTask::renderItems", buffer);
419 auto enginePermutation = renderer->getEnginePermutations().get(permutationIndex);
422 uint32_t frame = taskContext->context->time->getFrame();
423 uint32_t widthDivisor = taskContext->context->variables->get(
"renderer.oit.TemporalUpscaleWidth", 1);
424 uint32_t heightDivisor = taskContext->context->variables->get(
"renderer.oit.TemporalUpscaleHeight", 1);
425 uint32_t i = frame % (widthDivisor * heightDivisor);
426 uint32_t w = i%widthDivisor;
427 uint32_t h = (i/widthDivisor)%heightDivisor;
429 CameraData &viewportData(*(CameraData*)renderList->viewportData);
430 viewportData.projectionMatrix = taskContext->renderer->getProjectionMatrix(viewportData.rawProjectionMatrix);
431 viewportData.projectionMatrix[2][0] += (float)w*(2.0f/widthDivisor)/(float)renderTarget->width;
432 viewportData.projectionMatrix[2][1] -= (
float)h*(2.0f/heightDivisor)/(
float)renderTarget->height;
433 viewportData.viewProjection = viewportData.projectionMatrix * viewportData.viewMatrix;
434 viewportData.inverseViewProjectionMatrix = glm::inverse(viewportData.viewProjection);
435 viewportData.inverseProjectionMatrix = glm::inverse(viewportData.projectionMatrix);
438 DrawContext drawContext;
439 drawContext.context = taskContext->context;
440 drawContext.renderer = renderer;
441 drawContext.device = device;
442 drawContext.deviceContext = device->getImmediateContext();
443 drawContext.cameraData = renderList->viewportData;
444 drawContext.permutationIndex = enginePermutation->getIndex();
445 drawContext.permutation = enginePermutation;
446 drawContext.engineBuffers = &renderer->getEngineBuffers();
447 drawContext.renderTarget = renderTarget;
448 drawContext.taskContext = taskContext;
449 drawContext.task =
this;
450 drawContext.listObjectBuffer = renderList->listObjectBuffer;
451 drawContext.clipShapeCache = renderList->clipShapeCache;
453 bool batchObjectBuffer = drawContext.engineBuffers->objectBatch.count != 0;
454 const StringView batchObjectBufferKey =
"renderer.batchObjectBuffer";
455 if (Variable* var = drawContext.context->variables->get(batchObjectBufferKey); !var->isEmpty()) {
456 batchObjectBuffer = var->getBool();
459 drawContext.context->variables->set(batchObjectBufferKey, batchObjectBuffer);
463 if (drawContext.listObjectBuffer && drawContext.listObjectBuffer->isInUse()) {
464 objectBufferMode = ObjectBufferMode::List;
465 batchObjectBuffer =
false;
467 else if (drawContext.engineBuffers->objectBatch.count && batchObjectBuffer) {
468 objectBufferMode = ObjectBufferMode::Batched;
471 objectBufferMode = ObjectBufferMode::Single;
472 batchObjectBuffer =
false;
475 for (
size_t b = 0; b < size_t(BucketType::Count); b++) {
476 if ((BucketMask(1 << b) & bucketMask) == 0)
continue;
478 const RenderItems & items = renderList->buckets[b];
479 renderBatched(taskContext, drawContext, renderList, items, bucketMask, stateChangeMask, batchObjectBuffer);
483 CameraData &viewportData(*(CameraData*)renderList->viewportData);
484 viewportData.projectionMatrix = taskContext->renderer->getProjectionMatrix(viewportData.rawProjectionMatrix);
485 viewportData.viewProjection = viewportData.projectionMatrix * viewportData.viewMatrix;
486 viewportData.inverseViewProjectionMatrix = glm::inverse(viewportData.viewProjection);
487 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.