1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "RenderAPI/BsRenderTexture.h"
4#include "Error/BsException.h"
5#include "Image/BsTexture.h"
6#include "Managers/BsTextureManager.h"
7#include "Resources/BsResources.h"
8#include "CoreThread/BsCoreThread.h"
9#include <Private/RTTI/BsRenderTargetRTTI.h>
10
11namespace bs
12{
13 RenderTextureProperties::RenderTextureProperties(const RENDER_TEXTURE_DESC& desc, bool requiresFlipping)
14 {
15 UINT32 firstIdx = (UINT32)-1;
16 bool requiresHwGamma = false;
17 for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
18 {
19 HTexture texture = desc.colorSurfaces[i].texture;
20
21 if (!texture.isLoaded())
22 continue;
23
24 if (firstIdx == (UINT32)-1)
25 firstIdx = i;
26
27 requiresHwGamma |= texture->getProperties().isHardwareGammaEnabled();
28 }
29
30 if (firstIdx == (UINT32)-1)
31 {
32 HTexture texture = desc.depthStencilSurface.texture;
33 if (texture.isLoaded())
34 {
35 const TextureProperties& texProps = texture->getProperties();
36 construct(&texProps, desc.depthStencilSurface.numFaces, desc.depthStencilSurface.mipLevel,
37 requiresFlipping, false);
38 }
39 }
40 else
41 {
42 HTexture texture = desc.colorSurfaces[firstIdx].texture;
43
44 const TextureProperties& texProps = texture->getProperties();
45 construct(&texProps, desc.colorSurfaces[firstIdx].numFaces, desc.colorSurfaces[firstIdx].mipLevel,
46 requiresFlipping, requiresHwGamma);
47 }
48 }
49
50 RenderTextureProperties::RenderTextureProperties(const ct::RENDER_TEXTURE_DESC& desc, bool requiresFlipping)
51 {
52 UINT32 firstIdx = (UINT32)-1;
53 bool requiresHwGamma = false;
54 for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
55 {
56 SPtr<ct::Texture> texture = desc.colorSurfaces[i].texture;
57
58 if (texture == nullptr)
59 continue;
60
61 if (firstIdx == (UINT32)-1)
62 firstIdx = i;
63
64 requiresHwGamma |= texture->getProperties().isHardwareGammaEnabled();
65 }
66
67 if(firstIdx == (UINT32)-1)
68 {
69 SPtr<ct::Texture> texture = desc.depthStencilSurface.texture;
70 if(texture != nullptr)
71 {
72 const TextureProperties& texProps = texture->getProperties();
73 construct(&texProps, desc.depthStencilSurface.numFaces, desc.depthStencilSurface.mipLevel,
74 requiresFlipping, false);
75 }
76 }
77 else
78 {
79 SPtr<ct::Texture> texture = desc.colorSurfaces[firstIdx].texture;
80
81 const TextureProperties& texProps = texture->getProperties();
82 construct(&texProps, desc.colorSurfaces[firstIdx].numFaces, desc.colorSurfaces[firstIdx].mipLevel,
83 requiresFlipping, requiresHwGamma);
84 }
85 }
86
87 void RenderTextureProperties::construct(const TextureProperties* textureProps, UINT32 numSlices,
88 UINT32 mipLevel, bool requiresFlipping, bool hwGamma)
89 {
90 if (textureProps != nullptr)
91 {
92 PixelUtil::getSizeForMipLevel(textureProps->getWidth(), textureProps->getHeight(), textureProps->getDepth(),
93 mipLevel, width, height, numSlices);
94
95 numSlices *= numSlices;
96 multisampleCount = textureProps->getNumSamples();
97 }
98
99 isWindow = false;
100 requiresTextureFlipping = requiresFlipping;
101 this->hwGamma = hwGamma;
102 }
103
104 SPtr<RenderTexture> RenderTexture::create(const TEXTURE_DESC& desc,
105 bool createDepth, PixelFormat depthStencilFormat)
106 {
107 return TextureManager::instance().createRenderTexture(desc, createDepth, depthStencilFormat);
108 }
109
110 SPtr<RenderTexture> RenderTexture::create(const RENDER_TEXTURE_DESC& desc)
111 {
112 return TextureManager::instance().createRenderTexture(desc);
113 }
114
115 SPtr<ct::RenderTexture> RenderTexture::getCore() const
116 {
117 return std::static_pointer_cast<ct::RenderTexture>(mCoreSpecific);
118 }
119
120 RenderTexture::RenderTexture(const RENDER_TEXTURE_DESC& desc)
121 :mDesc(desc)
122 {
123 for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
124 {
125 if (desc.colorSurfaces[i].texture != nullptr)
126 mBindableColorTex[i] = desc.colorSurfaces[i].texture;
127 }
128
129 if (desc.depthStencilSurface.texture != nullptr)
130 mBindableDepthStencilTex = desc.depthStencilSurface.texture;
131 }
132
133 SPtr<ct::CoreObject> RenderTexture::createCore() const
134 {
135 ct::RENDER_TEXTURE_DESC coreDesc;
136
137 for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
138 {
139 ct::RENDER_SURFACE_DESC surfaceDesc;
140 if (mDesc.colorSurfaces[i].texture.isLoaded())
141 surfaceDesc.texture = mDesc.colorSurfaces[i].texture->getCore();
142
143 surfaceDesc.face = mDesc.colorSurfaces[i].face;
144 surfaceDesc.numFaces = mDesc.colorSurfaces[i].numFaces;
145 surfaceDesc.mipLevel = mDesc.colorSurfaces[i].mipLevel;
146
147 coreDesc.colorSurfaces[i] = surfaceDesc;
148 }
149
150 if (mDesc.depthStencilSurface.texture.isLoaded())
151 coreDesc.depthStencilSurface.texture = mDesc.depthStencilSurface.texture->getCore();
152
153 coreDesc.depthStencilSurface.face = mDesc.depthStencilSurface.face;
154 coreDesc.depthStencilSurface.numFaces = mDesc.depthStencilSurface.numFaces;
155 coreDesc.depthStencilSurface.mipLevel = mDesc.depthStencilSurface.mipLevel;
156
157 return ct::TextureManager::instance().createRenderTextureInternal(coreDesc);
158 }
159
160 CoreSyncData RenderTexture::syncToCore(FrameAlloc* allocator)
161 {
162 UINT32 size = sizeof(RenderTextureProperties);
163 UINT8* buffer = allocator->alloc(size);
164
165 RenderTextureProperties& props = const_cast<RenderTextureProperties&>(getProperties());
166
167 memcpy(buffer, (void*)&props, size);
168 return CoreSyncData(buffer, size);
169 }
170
171 const RenderTextureProperties& RenderTexture::getProperties() const
172 {
173 return static_cast<const RenderTextureProperties&>(getPropertiesInternal());
174 }
175
176 /************************************************************************/
177 /* SERIALIZATION */
178 /************************************************************************/
179
180 RTTITypeBase* RenderTexture::getRTTIStatic()
181 {
182 return RenderTextureRTTI::instance();
183 }
184
185 RTTITypeBase* RenderTexture::getRTTI() const
186 {
187 return RenderTexture::getRTTIStatic();
188 }
189
190 namespace ct
191 {
192 RenderTexture::RenderTexture(const RENDER_TEXTURE_DESC& desc, UINT32 deviceIdx)
193 :mDesc(desc)
194 { }
195
196 void RenderTexture::initialize()
197 {
198 RenderTarget::initialize();
199
200 for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
201 {
202 if (mDesc.colorSurfaces[i].texture != nullptr)
203 {
204 SPtr<Texture> texture = mDesc.colorSurfaces[i].texture;
205
206 if ((texture->getProperties().getUsage() & TU_RENDERTARGET) == 0)
207 BS_EXCEPT(InvalidParametersException, "Provided texture is not created with render target usage.");
208
209 mColorSurfaces[i] = texture->requestView(mDesc.colorSurfaces[i].mipLevel, 1,
210 mDesc.colorSurfaces[i].face, mDesc.colorSurfaces[i].numFaces, GVU_RENDERTARGET);
211 }
212 }
213
214 if (mDesc.depthStencilSurface.texture != nullptr)
215 {
216 SPtr<Texture> texture = mDesc.depthStencilSurface.texture;
217
218 if ((texture->getProperties().getUsage() & TU_DEPTHSTENCIL) == 0)
219 BS_EXCEPT(InvalidParametersException, "Provided texture is not created with depth stencil usage.");
220
221 mDepthStencilSurface = texture->requestView(mDesc.depthStencilSurface.mipLevel, 1,
222 mDesc.depthStencilSurface.face, mDesc.depthStencilSurface.numFaces, GVU_DEPTHSTENCIL);
223 }
224
225 throwIfBuffersDontMatch();
226 }
227
228 SPtr<RenderTexture> RenderTexture::create(const RENDER_TEXTURE_DESC& desc, UINT32 deviceIdx)
229 {
230 return TextureManager::instance().createRenderTexture(desc, deviceIdx);
231 }
232
233 void RenderTexture::syncToCore(const CoreSyncData& data)
234 {
235 RenderTextureProperties& props = const_cast<RenderTextureProperties&>(getProperties());
236 props = data.getData<RenderTextureProperties>();
237 }
238
239 const RenderTextureProperties& RenderTexture::getProperties() const
240 {
241 return static_cast<const RenderTextureProperties&>(getPropertiesInternal());
242 }
243
244 void RenderTexture::throwIfBuffersDontMatch() const
245 {
246 UINT32 firstSurfaceIdx = (UINT32)-1;
247 for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
248 {
249 if (mColorSurfaces[i] == nullptr)
250 continue;
251
252 if (firstSurfaceIdx == (UINT32)-1)
253 {
254 firstSurfaceIdx = i;
255 continue;
256 }
257
258 const TextureProperties& curTexProps = mDesc.colorSurfaces[i].texture->getProperties();
259 const TextureProperties& firstTexProps = mDesc.colorSurfaces[firstSurfaceIdx].texture->getProperties();
260
261 UINT32 curMsCount = curTexProps.getNumSamples();
262 UINT32 firstMsCount = firstTexProps.getNumSamples();
263
264 UINT32 curNumSlices = mColorSurfaces[i]->getNumArraySlices();
265 UINT32 firstNumSlices = mColorSurfaces[firstSurfaceIdx]->getNumArraySlices();
266
267 if (curMsCount == 0)
268 curMsCount = 1;
269
270 if (firstMsCount == 0)
271 firstMsCount = 1;
272
273 if (curTexProps.getWidth() != firstTexProps.getWidth() ||
274 curTexProps.getHeight() != firstTexProps.getHeight() ||
275 curTexProps.getDepth() != firstTexProps.getDepth() ||
276 curMsCount != firstMsCount ||
277 curNumSlices != firstNumSlices)
278 {
279 String errorInfo = "\nWidth: " + toString(curTexProps.getWidth()) + "/" + toString(firstTexProps.getWidth());
280 errorInfo += "\nHeight: " + toString(curTexProps.getHeight()) + "/" + toString(firstTexProps.getHeight());
281 errorInfo += "\nDepth: " + toString(curTexProps.getDepth()) + "/" + toString(firstTexProps.getDepth());
282 errorInfo += "\nNum. slices: " + toString(curNumSlices) + "/" + toString(firstNumSlices);
283 errorInfo += "\nMultisample Count: " + toString(curMsCount) + "/" + toString(firstMsCount);
284
285 BS_EXCEPT(InvalidParametersException, "Provided color textures don't match!" + errorInfo);
286 }
287 }
288
289 if (firstSurfaceIdx != (UINT32)-1)
290 {
291 const TextureProperties& firstTexProps = mDesc.colorSurfaces[firstSurfaceIdx].texture->getProperties();
292 SPtr<TextureView> firstSurfaceView = mColorSurfaces[firstSurfaceIdx];
293
294 UINT32 numSlices;
295 if (firstTexProps.getTextureType() == TEX_TYPE_3D)
296 numSlices = firstTexProps.getDepth();
297 else
298 numSlices = firstTexProps.getNumFaces();
299
300 if ((firstSurfaceView->getFirstArraySlice() + firstSurfaceView->getNumArraySlices()) > numSlices)
301 {
302 BS_EXCEPT(InvalidParametersException, "Provided number of faces is out of range. Face: " +
303 toString(firstSurfaceView->getFirstArraySlice() + firstSurfaceView->getNumArraySlices()) + ". Max num faces: " + toString(numSlices));
304 }
305
306 if (firstSurfaceView->getMostDetailedMip() > firstTexProps.getNumMipmaps())
307 {
308 BS_EXCEPT(InvalidParametersException, "Provided number of mip maps is out of range. Mip level: " +
309 toString(firstSurfaceView->getMostDetailedMip()) + ". Max num mipmaps: " + toString(firstTexProps.getNumMipmaps()));
310 }
311
312 if (mDepthStencilSurface == nullptr)
313 return;
314
315 const TextureProperties& depthTexProps = mDesc.depthStencilSurface.texture->getProperties();
316 UINT32 depthMsCount = depthTexProps.getNumSamples();
317 UINT32 colorMsCount = firstTexProps.getNumSamples();
318
319 if (depthMsCount == 0)
320 depthMsCount = 1;
321
322 if (colorMsCount == 0)
323 colorMsCount = 1;
324
325 if (depthTexProps.getWidth() != firstTexProps.getWidth() ||
326 depthTexProps.getHeight() != firstTexProps.getHeight() ||
327 depthMsCount != colorMsCount)
328 {
329 String errorInfo = "\nWidth: " + toString(depthTexProps.getWidth()) + "/" + toString(firstTexProps.getWidth());
330 errorInfo += "\nHeight: " + toString(depthTexProps.getHeight()) + "/" + toString(firstTexProps.getHeight());
331 errorInfo += "\nMultisample Count: " + toString(depthMsCount) + "/" + toString(colorMsCount);
332
333 BS_EXCEPT(InvalidParametersException, "Provided texture and depth stencil buffer don't match!" + errorInfo);
334 }
335 }
336 }
337 }
338}
339