Cogs.Core
RenderTexture.cpp
1#include "RenderTexture.h"
2
3#include "Rendering/IGraphicsDevice.h"
4#include "Rendering/ITextures.h"
5#include "Rendering/IContext.h"
6#include "Rendering/IRenderTargets.h"
7
8#include "Foundation/Logging/Logger.h"
9#include "Foundation/BitTwiddling/PowerOfTwo.h"
10
11#include "Resources/Texture.h"
12
13#include "Context.h"
14#include "Renderer.h"
15#include "RenderTarget.h"
16
17namespace
18{
19 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderTexture");
20
21 // Count the number of leading zeros.
22 uint32_t lzcnt(uint32_t x)
23 {
24 if (x == 0u) return (32u);
25 uint32_t n = 1u;
26 if ((x >> 16) == 0) { n += 16u; x = x << 16; }
27 if ((x >> 24) == 0) { n += 8u; x = x << 8; }
28 if ((x >> 28) == 0) { n += 4u; x = x << 4; }
29 if ((x >> 30) == 0) { n += 2u; x = x << 2; }
30 return n - (x >> 31);
31 }
32
33}
34
35Cogs::Core::RenderTexture::RenderTexture()
36{
37 type = RenderResourceType::RenderTexture;
38}
39
40Cogs::Core::ActivationResult Cogs::Core::RenderTexture::update(Texture * texture, IGraphicsDevice * device, RenderResources * /*renderResources*/)
41{
42 setResource(texture);
43
44 if (isOwned()) return ActivationResult::Success;
45
46 ITextures* textures = device->getTextures();
47 const bool isRenderTarget = (texture->description.flags & TextureFlags::RenderTarget) != 0;
48 const bool isDepthTarget = (texture->description.flags & TextureFlags::DepthBuffer) != 0;
49 const bool dimensionsChanged = texture->description.width != description.width ||
50 texture->description.target != description.target ||
51 texture->description.height != description.height ||
52 texture->description.depth != description.depth ||
53 texture->description.format != description.format ||
54 texture->description.layers != description.layers ||
55 texture->description.levels != description.levels ||
56 texture->description.faces != description.faces ||
57 texture->description.samples != description.samples ||
58 !HandleIsValid(textureHandle);
59
60 if (!dimensionsChanged) {
61 if (!isRenderTarget && !isDepthTarget) {
62 if (!texture->storage.data.empty()) {
63 if (device->getType() == Cogs::GraphicsDeviceType::OpenGL20 ||
64 device->getType() == Cogs::GraphicsDeviceType::OpenGLES30) // UploadTextureData is not implemented for all device types.
65 {
66 TextureExtent extent{
67 .width = description.width,
68 .height = description.height,
69 .depth = description.depth,
70 };
71 TextureData textureData(texture->storage.getData(), extent, description.layers, description.faces, description.levels, description.format);
72 textures->uploadTextureData(textureHandle, textureData);
73 }
74 else {
75 device->getImmediateContext()->updateSubTexture(textureHandle, 0, texture->storage.getData());
76
77 if (texture->description.flags & TextureFlags::GenerateMipMaps) {
78 textures->generateMipmaps(textureHandle);
79 }
80 }
81 }
82 }
83 } else {
84 if (HandleIsValid(textureHandle)) {
85 //TODO: Release resources correctly.
86 textures->releaseTexture(textureHandle);
87 renderTargets = {};
88 }
89
90 if (texture->externalHandle) {
91 texture->description.flags |= TextureFlags::ExternalTexture;
92 TextureData textureData;
93 textureData.initExternal(texture->externalHandle);
94 textureHandle = textures->loadTexture(texture->description, &textureData);
95 textures->annotate(textureHandle, getName());
96 }
97 else if (texture->ownsExternalTexture.value) {
98 LOG_TRACE(logger, "Clearing render texture handle");
99 textureHandle = Cogs::TextureHandle(); // External texture that shouldn't be used anymore.
100 setFailed();
102 }
103 else {
104 textureHandle = textures->loadTexture(texture->description, (isRenderTarget || isDepthTarget || !texture->storage.data.size()) ? nullptr : &texture->storage);
105 textures->annotate(textureHandle, getName());
106 }
107
108 description = texture->description;
109 }
110 texture->clearData();
111
112 if (!HandleIsValid(textureHandle)) {
113 LOG_ERROR(logger, "Failed to create texture.");
114
115 setFailed();
116
118 }
119
120 incrementGeneration();
121 setActive();
122
124}
125
126void Cogs::Core::RenderTexture::release(Renderer * renderer)
127{
128 auto device = renderer->getDevice();
129
130 if (renderTarget) {
131 renderer->getRenderResources().releaseResource(renderTarget);
132 renderTarget = nullptr;
133 }
134
135 if (depthTexture) {
136 renderer->getRenderResources().releaseResource(depthTexture);
137 depthTexture = nullptr;
138 }
139
140 auto textures = device->getTextures();
141
142 for (auto & view : views) {
143 textures->releaseTextureView(view.second);
144 }
145
146 views.clear();
147
148 if (HandleIsValid(textureHandle)) {
149 textures->releaseTexture(textureHandle);
150
151 setReleased();
152
153 textureHandle = Cogs::TextureHandle::NoHandle;
154 }
155}
156
157void Cogs::Core::RenderTexture::update(Renderer * renderer)
158{
159 auto device = renderer->getDevice();
160 auto textures = device->getTextures();
161
162 // By default we size textures to the back buffer size.
163 auto targetSize = renderer->getSize();
164
165 if (isOverride()) return;
166
167 float scale = 1.0f;
168 uint32_t targetWidth = (uint32_t)(scale * (float)targetSize.x);
169 uint32_t targetHeight = (uint32_t)(scale * (float)targetSize.y);
170 uint32_t targetSamples = 0;
171
172 if (sizeSource) {
173 if (sizeSource->getType() == RenderResourceType::RenderTexture) {
174 targetWidth = static_cast<RenderTexture *>(sizeSource)->description.width;
175 targetHeight = static_cast<RenderTexture *>(sizeSource)->description.height;
176 targetSamples = static_cast<RenderTexture *>(sizeSource)->description.samples;
177 }
178 else {
179 targetWidth = static_cast<RenderTarget *>(sizeSource)->width;
180 targetHeight = static_cast<RenderTarget *>(sizeSource)->height;
181 targetSamples = static_cast<RenderTarget *>(sizeSource)->samples;
182 }
183 }
184 else if (width != 0 && height != 0) {
185 targetWidth = static_cast<int>(width);
186 targetHeight = static_cast<int>(height);
187 targetSamples = static_cast<uint32_t>(samples);
188 }
189 else {
190 targetSamples = static_cast<uint32_t>(samples);
191 }
192
193 // Maximum number of mipmap levels, power of two of largest size, rounded down.
194 uint32_t maxSize = static_cast<uint32_t>(std::max(targetWidth, targetHeight));
195 uint32_t maxLevels = 31 - std::min(31u, lzcnt(maxSize));
196 assert((maxSize == 0) || ((1u << maxLevels) <= maxSize));
197 assert(maxSize <= (1u << (maxLevels + 1)));
198 uint32_t targetLevels = std::min(maxLevels, static_cast<uint32_t>(levels.getValue() == 0 ? 1 : levels.getValue()));
199
200 // Only 1 or 6 are acceptable values.
201 uint32_t targetFaces = 1;
202 if (faces == 6) targetFaces = 6;
203
204 uint32_t targetLayers = static_cast<uint32_t>(layers.getValue() == 0 ? 1 : layers.getValue());
205
206 if (!targetWidth || !targetHeight) return;
207
208 if (targetWidth == description.width &&
209 targetHeight == description.height &&
210 targetLevels == description.levels &&
211 targetFaces == description.faces &&
212 targetLayers == description.layers &&
213 targetSamples == description.samples) return;
214
215 release(renderer);
216
217 description.width = targetWidth;
218 description.height = targetHeight;
219 description.levels = targetLevels;
220 description.faces = targetFaces;
221 description.layers = targetLayers;
222 description.samples = targetSamples;
223 if (description.target == ResourceDimensions::Texture2D && description.samples > 1) {
224 description.target = ResourceDimensions::Texture2DMS;
225 }
226
227 textureHandle = textures->loadTexture(description, nullptr);
228
229 textures->annotate(textureHandle, getName());
230
231 incrementGeneration();
232}
Log implementation class.
Definition: LogManager.h:139
ActivationResult
Defines results for resource activation.
Definition: ResourceBase.h:14
@ Success
Resource activated successfully.
@ Failure
Resource activation failed.
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
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ OpenGL20
Graphics device using OpenGL, supporting at least OpenGL 2.0.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
Definition: Flags.h:122
@ RenderTarget
The texture can be used as a render target and drawn into.
Definition: Flags.h:120
@ GenerateMipMaps
The texture supports automatic mipmap generation performed by the graphics device.
Definition: Flags.h:124