Cogs.Core
MipLevelsTask.cpp
1#include "MipLevelsTask.h"
2
3#include "Rendering/IGraphicsDevice.h"
4#include "Rendering/IBuffers.h"
5#include "Rendering/IContext.h"
6#include "Rendering/SamplerState.h"
7#include "Rendering/ITextures.h"
8
9#include "Renderer/RenderTarget.h"
10#include "Renderer/RenderTexture.h"
11
12#include "Resources/VertexFormats.h"
13
14#include "Utilities/Parsing.h"
15
16using namespace Cogs;
17
18namespace
19{
20 struct MipLevelsParameter
21 {
22 glm::vec2 srcTexelSize;
23 glm::vec2 dstTexelSize;
24 int srcLevel;
25 int dstLevel;
26 };
27}
28void Cogs::Core::MipLevelsTask::initialize(RenderTaskContext* context)
29{
30 PostProcessTask::initialize(context);
31}
32
33void Cogs::Core::MipLevelsTask::initialize(RenderTaskContext * context, const RenderTaskDefinition& taskDefinition)
34{
35 PostProcessTask::initialize(context, taskDefinition);
36 if (effect == nullptr || !HandleIsValid(effect->handle)) return;
37
38 auto device = context->renderer->getDevice();
39 auto effects = device->getEffects();
40 auto buffers = device->getBuffers();
41
42 parameterHandle = buffers->loadBuffer(nullptr, sizeof(MipLevelsParameter), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
43 parameterBufferBinding = effects->getConstantBufferBinding(effect->handle, "MipLevelsParameter");
44}
45
46void Cogs::Core::MipLevelsTask::cleanup(RenderTaskContext * context)
47{
48 auto device = context->renderer->getDevice();
49 auto buffers = device->getBuffers();
50 buffers->releaseBuffer(parameterHandle);
51 PostProcessTask::cleanup(context);
52}
53
54void Cogs::Core::MipLevelsTask::apply(RenderTaskContext * context)
55{
56 DynamicRenderInstrumentationScope(context->device->getImmediateContext(), SCOPE_RENDERING, "MipLevelsTask", (std::string("MipLevelsTask<") + name + ">::apply").c_str());
57
58 if (effect == nullptr || !HandleIsValid(effect->handle)) return;
59
60 auto device = context->renderer->getDevice();
61 auto deviceContext = device->getImmediateContext();
62 auto effects = device->getEffects();
63
64 auto renderTarget = output.get(RenderResourceType::RenderTarget)->renderTarget;
65 auto targetSource = renderTarget->textures[0];
66
67 std::string targetSourceKey;
68 for (auto & p : properties) {
69 if (p.definition->type == ParsedDataType::Texture2D) {
70 auto inputSource = input.get(p.definition->value);
71 RenderTexture* tex = nullptr;
72 if (inputSource->type == RenderResourceType::RenderTexture) {
73 tex = inputSource->renderTexure;
74 }
75 else if (inputSource->type == RenderResourceType::RenderTarget) {
76 tex = inputSource->renderTarget->textures[0];
77 }
78 if (tex) {
79 targetSourceKey = p.definition->key;
80 }
81 }
82 }
83
84 size_t maxLevel = std::max(size_t(1u), renderTarget->mipLevelViews.size());
85 if (sizes.size() != maxLevel || sizes[0].x != renderTarget->width || sizes[0].y != renderTarget->height) {
86 sizes.resize(maxLevel);
87 sizes[0] = glm::ivec2(renderTarget->width, renderTarget->height);
88 for (uint32_t i = 1; i < maxLevel; i++) {
89 sizes[i] = glm::ivec2(std::max(1, sizes[i - 1].x / 2), std::max(1, sizes[i - 1].y / 2));
90 }
91 }
92
93 deviceContext->setEffect(effect->handle);
94 deviceContext->setDepthStencilState(context->states->noDepthStencilStateHandle);
95 deviceContext->setRasterizerState(context->states->defaultRasterizerStateHandle);
96
97 for (size_t i = 0; i < 4; ++i) {
98 if (HandleIsValid(samplerStateBindings[i])) {
99 deviceContext->setSamplerState(samplerStateBindings[i], samplerStates[i]);
100 }
101 }
102
103 setProperties(context, targetSource);
104
106 if (!targetSourceKey.empty()) {
107 SamplerState ss;
108 std::memset(&ss, 0, sizeof(SamplerState));
113
114 targetSourceHandle = effects->getTextureBinding(effect->handle, targetSourceKey, texUnit);
115 deviceContext->setSamplerState(targetSourceKey + "Sampler", texUnit, context->states->getSamplerState(ss));
116
117 texUnit++;
118 }
119
120 if (!HandleIsValid(targetSourceHandle)) {
121 //TODO: Log warning
122 return;
123 }
124
125 size_t currentFirstLevel = std::min(maxLevel - 1u, static_cast<size_t>(firstLevel));
126 size_t currentLastLevel = std::min(maxLevel - 1u, static_cast<size_t>(lastLevel));
127 if (currentFirstLevel < currentLastLevel) {
128 for (size_t l = currentFirstLevel; l < currentLastLevel; l++) {
129 const size_t srcLevel = l;
130 const size_t dstLevel = l + 1;
131
132
133 {
134 MappedBuffer<MipLevelsParameter> parameters(deviceContext, parameterHandle, MapMode::WriteDiscard);
135
136 if (parameters) {
137 parameters->srcTexelSize = glm::vec2(1.f) / glm::vec2(sizes[srcLevel]);
138 parameters->dstTexelSize = glm::vec2(1.f) / glm::vec2(sizes[dstLevel]);
139 parameters->srcLevel = static_cast<int>(srcLevel);
140 parameters->dstLevel = static_cast<int>(dstLevel);
141 }
142 }
143
144 deviceContext->setConstantBuffer(parameterBufferBinding, parameterHandle);
145
146 deviceContext->setRenderTarget(renderTarget->mipLevelViews[dstLevel], DepthStencilHandle::NoHandle);
147
148 // Why must it be done after setRenderTarget (WebGPU)
149 deviceContext->setVertexBuffers(&context->states->fullScreenTriangle, 1);
150 deviceContext->setIndexBuffer(IndexBufferHandle::NoHandle);
151 deviceContext->setInputLayout(inputLayout);
152
153
154 TextureViewDescription textureViewDesc = {};
155 textureViewDesc.texture = targetSource->textureHandle;
156 textureViewDesc.levelIndex = static_cast<uint32_t>(srcLevel);
157 textureViewDesc.numLevels = 1;
158 textureViewDesc.numLayers = 1;
159
160 size_t code = textureViewDesc.hash();
161
162 auto found = targetSource->views.find(code);
163
164 Cogs::TextureViewHandle textureView;
165
166 if (found == targetSource->views.end()) {
167 textureView = device->getTextures()->createTextureView(textureViewDesc);
168 targetSource->views.insert({ code, textureView });
169 } else {
170 textureView = found->second;
171 }
172
173 deviceContext->setTexture(targetSourceHandle, textureView);
174
175 deviceContext->setViewport(0, 0, (float)sizes[dstLevel].x, (float)sizes[dstLevel].y);
176
177 deviceContext->draw(PrimitiveType::TriangleList, 0, 3);
178 }
179 } else if (currentLastLevel < currentFirstLevel) {
180 for (size_t l = currentFirstLevel; currentLastLevel < l; l--) {
181 const size_t srcLevel = l;
182 const size_t dstLevel = l - 1;
183
184 {
185 MappedBuffer<MipLevelsParameter> parameters(deviceContext, parameterHandle, MapMode::WriteDiscard);
186
187 if (parameters) {
188 parameters->srcTexelSize = glm::vec2(1.f) / glm::vec2(sizes[srcLevel]);
189 parameters->dstTexelSize = glm::vec2(1.f) / glm::vec2(sizes[dstLevel]);
190 parameters->srcLevel = static_cast<int>(srcLevel);
191 parameters->dstLevel = static_cast<int>(dstLevel);
192 }
193 }
194
195 deviceContext->setConstantBuffer(parameterBufferBinding, parameterHandle);
196 deviceContext->setRenderTarget(renderTarget->mipLevelViews[dstLevel], DepthStencilHandle::NoHandle);
197
198 TextureViewDescription textureViewDesc = {};
199 textureViewDesc.texture = targetSource->textureHandle;
200 textureViewDesc.levelIndex = static_cast<uint32_t>(srcLevel);
201 textureViewDesc.numLevels = 1;
202
203 size_t code = textureViewDesc.hash();
204
205 auto found = targetSource->views.find(code);
206
207 Cogs::TextureViewHandle textureView;
208
209 if (found == targetSource->views.end()) {
210 textureView = device->getTextures()->createTextureView(textureViewDesc);
211 targetSource->views.insert({ code, textureView });
212 } else {
213 textureView = found->second;
214 }
215
216 deviceContext->setTexture(targetSourceHandle, textureView);
217
218 deviceContext->setViewport(0, 0, (float)sizes[dstLevel].x, (float)sizes[dstLevel].y);
219
220 deviceContext->draw(PrimitiveType::TriangleList, 0, 3);
221 }
222 }
223}
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ TriangleList
List of triangles.
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
Provides RAII style mapping of a buffer resource.
Definition: IBuffers.h:160
Encapsulates state for texture sampling in a state object.
Definition: SamplerState.h:12
AddressMode addressModeW
Specifies the addressing mode along the W axis in texture coordinate space.
Definition: SamplerState.h:67
AddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
Definition: SamplerState.h:63
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
Definition: SamplerState.h:17
@ MinMagMipLinear
Linear sampling for both minification and magnification.
Definition: SamplerState.h:35
FilterMode filter
Specifies the filter to use for texture sampling.
Definition: SamplerState.h:70
AddressMode addressModeT
Specifies the addressing mode along the T axis in texture coordinate space.
Definition: SamplerState.h:65
Describes how to fetch data from a texture in shaders.
Definition: ITextures.h:13
uint32_t numLayers
Number of array layers available.
Definition: ITextures.h:19
uint32_t numLevels
Number of mipmap levels available.
Definition: ITextures.h:23
uint32_t levelIndex
First mipmap level to fetch data from.
Definition: ITextures.h:21
TextureHandle texture
Texture.
Definition: ITextures.h:15
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30