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 release(device, renderResources);
85
86 if (texture->externalHandle) {
87 texture->description.flags |= TextureFlags::ExternalTexture;
88 TextureData textureData;
89 textureData.initExternal(texture->externalHandle);
90 textureHandle = textures->loadTexture(texture->description, &textureData);
91 textures->annotate(textureHandle, getName());
92 }
93 else if (texture->ownsExternalTexture.value) {
94 LOG_TRACE(logger, "Clearing render texture handle");
95 textureHandle = Cogs::TextureHandle(); // External texture that shouldn't be used anymore.
96 setFailed();
98 }
99 else {
100 textureHandle = textures->loadTexture(texture->description, (isRenderTarget || isDepthTarget || !texture->storage.data.size()) ? nullptr : &texture->storage);
101 textures->annotate(textureHandle, getName());
102 }
103
104 description = texture->description;
105 }
106 texture->clearData();
107
108 if (!HandleIsValid(textureHandle)) {
109 LOG_ERROR(logger, "Failed to create texture.");
110
111 setFailed();
112
114 }
115
116 incrementGeneration();
117 setActive();
118
120}
121
122void Cogs::Core::RenderTexture::release(IGraphicsDevice * device, RenderResources * resources)
123{
124 if (renderTarget) {
125 resources->releaseResource(renderTarget);
126 renderTarget = nullptr;
127 }
128 if (resolveTarget) {
129 resources->releaseResource(resolveTarget);
130 resolveTarget = nullptr;
131 }
132
133 if (depthTexture) {
134 resources->releaseResource(depthTexture);
135 depthTexture = nullptr;
136 }
137
138 auto textures = device->getTextures();
139
140 for (auto & view : views) {
141 textures->releaseTextureView(view.second);
142 }
143 views.clear();
144
145 if (HandleIsValid(textureHandle)) {
146 textures->releaseTexture(textureHandle);
147 textureHandle = Cogs::TextureHandle::NoHandle;
148 }
149}
150
151void Cogs::Core::RenderTexture::release(Renderer * renderer)
152{
153 release(renderer->getDevice(), &renderer->getRenderResources());
154 setReleased();
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 = static_cast<uint32_t>(samples);
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 }
177 else {
178 targetWidth = static_cast<RenderTarget *>(sizeSource)->width;
179 targetHeight = static_cast<RenderTarget *>(sizeSource)->height;
180 }
181 }
182 else{
183 int iw = static_cast<int>(width);
184 int ih = static_cast<int>(height);
185 if((description.width != (uint32_t)std::max(iw, 2)) && iw < 2){
186 LOG_WARNING(logger, "Render texture, width %d < 2. (Clamping to 2).", iw);
187 }
188 if((description.height != (uint32_t)std::max(ih, 2)) && ih < 2){
189 LOG_WARNING(logger, "Render texture, height %d < 2. (Clamping to 2).", ih);
190 }
191 targetWidth = std::max(iw, 2);
192 targetHeight = std::max(ih, 2);
193 }
194
195 // Maximum number of mipmap levels, power of two of largest size, rounded down.
196 uint32_t maxSize = static_cast<uint32_t>(std::max(targetWidth, targetHeight));
197 uint32_t maxLevels = 31 - std::min(31u, lzcnt(maxSize));
198 assert((maxSize == 0) || ((1u << maxLevels) <= maxSize));
199 assert(maxSize <= (1u << (maxLevels + 1)));
200 uint32_t targetLevels = std::min(maxLevels, static_cast<uint32_t>(levels.getValue() == 0 ? 1 : levels.getValue()));
201
202 // Only 1 or 6 are acceptable values.
203 uint32_t targetFaces = 1;
204 if (faces == 6) targetFaces = 6;
205
206 uint32_t targetLayers = static_cast<uint32_t>(layers.getValue() == 0 ? 1 : layers.getValue());
207
208 if (!targetWidth || !targetHeight) return;
209
210 if (targetWidth == description.width &&
211 targetHeight == description.height &&
212 targetLevels == description.levels &&
213 targetFaces == description.faces &&
214 targetLayers == description.layers &&
215 targetSamples == description.samples) return;
216
217 release(renderer);
218
219 description.width = targetWidth;
220 description.height = targetHeight;
221 description.levels = targetLevels;
222 description.faces = targetFaces;
223 description.layers = targetLayers;
224 description.samples = targetSamples;
225 if (description.target == ResourceDimensions::Texture2D && description.samples > 1) {
226 description.target = ResourceDimensions::Texture2DMS;
227 }
228 if (description.target == ResourceDimensions::Texture2DMS && description.samples == 1) {
229 description.target = ResourceDimensions::Texture2D;
230 }
231
232 textureHandle = textures->loadTexture(description, nullptr);
233
234 textures->annotate(textureHandle, getName());
235
236 incrementGeneration();
237}
Log implementation class.
Definition: LogManager.h:140
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:181
@ 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:78
@ 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