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#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Resources/BsResource.h"
7#include "RenderAPI/BsHardwareBuffer.h"
8#include "Image/BsPixelUtil.h"
9#include "RenderAPI/BsTextureView.h"
10#include "Math/BsVector3I.h"
11
12namespace bs
13{
14 /** @addtogroup Resources
15 * @{
16 */
17
18 /** Flags that describe how is a texture used. */
19 enum BS_SCRIPT_EXPORT(m:Rendering) TextureUsage
20 {
21 /** A regular texture that is not often or ever updated from the CPU. */
22 TU_STATIC BS_SCRIPT_EXPORT(n:Default) = GBU_STATIC,
23 /** A regular texture that is often updated by the CPU. */
24 TU_DYNAMIC BS_SCRIPT_EXPORT(n:Dynamic) = GBU_DYNAMIC,
25 /** Texture that can be rendered to by the GPU. */
26 TU_RENDERTARGET BS_SCRIPT_EXPORT(n:Render) = 0x200,
27 /** Texture used as a depth/stencil buffer by the GPU. */
28 TU_DEPTHSTENCIL BS_SCRIPT_EXPORT(n:DepthStencil) = 0x400,
29 /** Texture that allows load/store operations from the GPU program. */
30 TU_LOADSTORE BS_SCRIPT_EXPORT(n:LoadStore) = 0x800,
31 /** All mesh data will also be cached in CPU memory, making it available for fast read access from the CPU. */
32 TU_CPUCACHED BS_SCRIPT_EXPORT(n:CPUCached) = 0x1000,
33 /** Allows the CPU to directly read the texture data buffers from the GPU. */
34 TU_CPUREADABLE BS_SCRIPT_EXPORT(n:CPUReadable) = 0x2000,
35 /** Allows you to retrieve views of the texture using a format different from one specified on creation. */
36 TU_MUTABLEFORMAT BS_SCRIPT_EXPORT(n:MutableFormat) = 0x4000,
37 /** Default (most common) texture usage. */
38 TU_DEFAULT BS_SCRIPT_EXPORT(ex:true) = TU_STATIC
39 };
40
41 /** Texture mipmap options. */
42 enum TextureMipmap
43 {
44 MIP_UNLIMITED = 0x7FFFFFFF /**< Create all mip maps down to 1x1. */
45 };
46
47 /** Descriptor structure used for initialization of a Texture. */
48 struct TEXTURE_DESC
49 {
50 /** Type of the texture. */
51 TextureType type = TEX_TYPE_2D;
52
53 /** Format of pixels in the texture. */
54 PixelFormat format = PF_RGBA8;
55
56 /** Width of the texture in pixels. */
57 UINT32 width = 1;
58
59 /** Height of the texture in pixels. */
60 UINT32 height = 1;
61
62 /** Depth of the texture in pixels (Must be 1 for 2D textures). */
63 UINT32 depth = 1;
64
65 /** Number of mip-maps the texture has. This number excludes the full resolution map. */
66 UINT32 numMips = 0;
67
68 /** Describes how the caller plans on using the texture in the pipeline. */
69 INT32 usage = TU_DEFAULT;
70
71 /**
72 * If true the texture data is assumed to have been gamma corrected and will be converted back to linear space when
73 * sampled on GPU.
74 */
75 bool hwGamma = false;
76
77 /** Number of samples per pixel. Set to 1 or 0 to use the default of a single sample per pixel. */
78 UINT32 numSamples = 0;
79
80 /** Number of texture slices to create if creating a texture array. Ignored for 3D textures. */
81 UINT32 numArraySlices = 1;
82 };
83
84 /** Structure used for specifying information about a texture copy operation. */
85 struct TEXTURE_COPY_DESC
86 {
87 /**
88 * Face from which to copy. This can be an entry in an array of textures, or a single face of a cube map. If cubemap
89 * array, then each array entry takes up six faces.
90 */
91 UINT32 srcFace = 0;
92
93 /** Mip level from which to copy. */
94 UINT32 srcMip = 0;
95
96 /** Pixel volume from which to copy from. This defaults to all pixels of the face. */
97 PixelVolume srcVolume = PixelVolume(0, 0, 0, 0, 0, 0);
98
99 /**
100 * Face to which to copy. This can be an entry in an array of textures, or a single face of a cube map. If cubemap
101 * array, then each array entry takes up six faces.
102 */
103 UINT32 dstFace = 0;
104
105 /** Mip level to which to copy. */
106 UINT32 dstMip = 0;
107
108 /**
109 * Coordinates to write the source pixels to. The destination texture must have enough pixels to fit the entire
110 * source volume.
111 */
112 Vector3I dstPosition;
113
114 BS_CORE_EXPORT static TEXTURE_COPY_DESC DEFAULT;
115 };
116
117 /** Properties of a Texture. Shared between sim and core thread versions of a Texture. */
118 class BS_CORE_EXPORT TextureProperties
119 {
120 public:
121 TextureProperties() = default;
122 TextureProperties(const TEXTURE_DESC& desc);
123
124 /** Gets the type of texture. */
125 TextureType getTextureType() const { return mDesc.type; }
126
127 /**
128 * Gets the number of mipmaps to be used for this texture. This number excludes the top level map (which is always
129 * assumed to be present).
130 */
131 UINT32 getNumMipmaps() const { return mDesc.numMips; }
132
133 /**
134 * Determines does the texture contain gamma corrected data. If true then the GPU will automatically convert the
135 * pixels to linear space before reading from the texture, and convert them to gamma space when writing to the
136 * texture.
137 */
138 bool isHardwareGammaEnabled() const { return mDesc.hwGamma; }
139
140 /** Gets the number of samples used for multisampling (0 or 1 if multisampling is not used). */
141 UINT32 getNumSamples() const { return mDesc.numSamples; }
142
143 /** Returns the height of the texture. */
144 UINT32 getHeight() const { return mDesc.height; }
145
146 /** Returns the width of the texture. */
147 UINT32 getWidth() const { return mDesc.width; }
148
149 /** Returns the depth of the texture (only applicable for 3D textures). */
150 UINT32 getDepth() const { return mDesc.depth; }
151
152 /** Returns a value that signals the engine in what way is the texture expected to be used. */
153 int getUsage() const { return mDesc.usage; }
154
155 /** Returns the pixel format for the texture surface. */
156 PixelFormat getFormat() const { return mDesc.format; }
157
158 /** Returns true if the texture has an alpha layer. */
159 bool hasAlpha() const;
160
161 /**
162 * Returns the number of faces this texture has. This includes array slices (if texture is an array texture),
163 * as well as cube-map faces.
164 */
165 UINT32 getNumFaces() const;
166
167 /** Returns the number of array slices of the texture (if the texture is an array texture). */
168 UINT32 getNumArraySlices() const { return mDesc.numArraySlices; }
169
170 /**
171 * Allocates a buffer that exactly matches the format of the texture described by these properties, for the provided
172 * face and mip level. This is a helper function, primarily meant for creating buffers when reading from, or writing
173 * to a texture.
174 *
175 * @note Thread safe.
176 */
177 SPtr<PixelData> allocBuffer(UINT32 face, UINT32 mipLevel) const;
178
179 protected:
180 friend class TextureRTTI;
181 friend class Texture;
182
183 /**
184 * Maps a sub-resource index to an exact face and mip level. Sub-resource indexes are used when reading or writing
185 * to the resource.
186 */
187 void mapFromSubresourceIdx(UINT32 subresourceIdx, UINT32& face, UINT32& mip) const;
188
189 /**
190 * Map a face and a mip level to a sub-resource index you can use for updating or reading a specific sub-resource.
191 */
192 UINT32 mapToSubresourceIdx(UINT32 face, UINT32 mip) const;
193
194 TEXTURE_DESC mDesc;
195 };
196
197 /**
198 * Abstract class representing a texture. Specific render systems have their own Texture implementations. Internally
199 * represented as one or more surfaces with pixels in a certain number of dimensions, backed by a hardware buffer.
200 *
201 * @note Sim thread.
202 */
203 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Rendering) Texture : public Resource
204 {
205 public:
206 /**
207 * Updates the texture with new data. Provided data buffer will be locked until the operation completes.
208 *
209 * @param[in] data Pixel data to write. User must ensure it is in format and size compatible with
210 * the texture.
211 * @param[in] face Texture face to write to.
212 * @param[in] mipLevel Mipmap level to write to.
213 * @param[in] discardEntireBuffer When true the existing contents of the resource you are updating will be
214 * discarded. This can make the operation faster. Resources with certain buffer
215 * types might require this flag to be in a specific state otherwise the operation
216 * will fail.
217 * @return Async operation object you can use to track operation completion.
218 *
219 * @note This is an @ref asyncMethod "asynchronous method".
220 */
221 AsyncOp writeData(const SPtr<PixelData>& data, UINT32 face = 0, UINT32 mipLevel = 0,
222 bool discardEntireBuffer = false);
223
224 /**
225 * Reads internal texture data to the provided previously allocated buffer. Provided data buffer will be locked
226 * until the operation completes.
227 *
228 * @param[out] data Pre-allocated buffer of proper size and format where data will be read to. You can use
229 * TextureProperties::allocBuffer() to allocate a buffer of a correct format and size.
230 * @param[in] face Texture face to read from.
231 * @param[in] mipLevel Mipmap level to read from.
232 * @return Async operation object you can use to track operation completion.
233 *
234 * @note This is an @ref asyncMethod "asynchronous method".
235 */
236 AsyncOp readData(const SPtr<PixelData>& data, UINT32 face = 0, UINT32 mipLevel = 0);
237
238 /**
239 * Reads internal texture data into a newly allocated buffer.
240 *
241 * @param[in] face Texture face to read from.
242 * @param[in] mipLevel Mipmap level to read from.
243 * @return Async operation object that will contain the buffer with the data once the operation
244 * completes.
245 *
246 * @note This is an @ref asyncMethod "asynchronous method".
247 */
248 BS_SCRIPT_EXPORT(n:GetGPUPixels)
249 TAsyncOp<SPtr<PixelData>> readData(UINT32 face = 0, UINT32 mipLevel = 0);
250
251 /**
252 * Reads data from the cached system memory texture buffer into the provided buffer.
253 *
254 * @param[out] data Pre-allocated buffer of proper size and format where data will be read to. You can use
255 * TextureProperties::allocBuffer() to allocate a buffer of a correct format and size.
256 * @param[in] face Texture face to read from.
257 * @param[in] mipLevel Mipmap level to read from.
258 *
259 * @note
260 * The data read is the cached texture data. Any data written to the texture from the GPU or core thread will not
261 * be reflected in this data. Use readData() if you require those changes.
262 * @note
263 * The texture must have been created with TU_CPUCACHED usage otherwise this method will not return any data.
264 */
265 void readCachedData(PixelData& data, UINT32 face = 0, UINT32 mipLevel = 0);
266
267 /** Returns properties that contain information about the texture. */
268 const TextureProperties& getProperties() const { return mProperties; }
269
270 /** Retrieves a core implementation of a texture usable only from the core thread. */
271 SPtr<ct::Texture> getCore() const;
272
273 /************************************************************************/
274 /* STATICS */
275 /************************************************************************/
276
277 /**
278 * Creates a new empty texture.
279 *
280 * @param[in] desc Description of the texture to create.
281 */
282 static HTexture create(const TEXTURE_DESC& desc);
283
284 /**
285 * Creates a new 2D or 3D texture initialized using the provided pixel data. Texture will not have any mipmaps.
286 *
287 * @param[in] pixelData Data to initialize the texture width.
288 * @param[in] usage Describes planned texture use.
289 * @param[in] hwGammaCorrection If true the texture data is assumed to have been gamma corrected and will be
290 * converted back to linear space when sampled on GPU.
291 */
292 static HTexture create(const SPtr<PixelData>& pixelData, int usage = TU_DEFAULT, bool hwGammaCorrection = false);
293
294 /** @name Internal
295 * @{
296 */
297
298 /** Same as create() excepts it creates a pointer to the texture instead of a texture handle. */
299 static SPtr<Texture> _createPtr(const TEXTURE_DESC& desc);
300
301 /** Same as create() excepts it creates a pointer to the texture instead of a texture handle. */
302 static SPtr<Texture> _createPtr(const SPtr<PixelData>& pixelData, int usage = TU_DEFAULT,
303 bool hwGammaCorrection = false);
304
305 /** @} */
306
307 protected:
308 friend class TextureManager;
309
310 Texture(const TEXTURE_DESC& desc);
311 Texture(const TEXTURE_DESC& desc, const SPtr<PixelData>& pixelData);
312
313 /** @copydoc Resource::initialize */
314 void initialize() override;
315
316 /** @copydoc CoreObject::createCore */
317 SPtr<ct::CoreObject> createCore() const override;
318
319 /** Calculates the size of the texture, in bytes. */
320 UINT32 calculateSize() const;
321
322 /**
323 * Creates buffers used for caching of CPU texture data.
324 *
325 * @note Make sure to initialize all texture properties before calling this.
326 */
327 void createCPUBuffers();
328
329 /** Updates the cached CPU buffers with new data. */
330 void updateCPUBuffers(UINT32 subresourceIdx, const PixelData& data);
331
332 protected:
333 Vector<SPtr<PixelData>> mCPUSubresourceData;
334 TextureProperties mProperties;
335 mutable SPtr<PixelData> mInitData;
336
337 /************************************************************************/
338 /* SERIALIZATION */
339 /************************************************************************/
340 public:
341 Texture() = default; // Serialization only
342
343 friend class TextureRTTI;
344 static RTTITypeBase* getRTTIStatic();
345 RTTITypeBase* getRTTI() const override;
346 };
347
348 /** @} */
349
350 namespace ct
351 {
352 /** @addtogroup Resources-Internal
353 * @{
354 */
355
356 /**
357 * Core thread version of a bs::Texture.
358 *
359 * @note Core thread.
360 */
361 class BS_CORE_EXPORT Texture : public CoreObject
362 {
363 public:
364 Texture(const TEXTURE_DESC& desc, const SPtr<PixelData>& initData, GpuDeviceFlags deviceMask);
365 virtual ~Texture() {}
366
367
368 /** @copydoc CoreObject::initialize */
369 void initialize() override;
370
371 /**
372 * Locks the buffer for reading or writing.
373 *
374 * @param[in] options Options for controlling what you may do with the locked data.
375 * @param[in] mipLevel (optional) Mipmap level to lock.
376 * @param[in] face (optional) Texture face to lock.
377 * @param[in] deviceIdx Index of the device whose memory to map. If the buffer doesn't exist on this device,
378 * the method returns null.
379 * @param[in] queueIdx Device queue to perform the read/write operations on. See @ref queuesDoc.
380 *
381 * @note
382 * If you are just reading or writing one block of data use readData()/writeData() methods as they can be much faster
383 * in certain situations.
384 */
385 PixelData lock(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
386 UINT32 queueIdx = 0);
387
388 /**
389 * Unlocks a previously locked buffer. After the buffer is unlocked, any data returned by lock becomes invalid.
390 *
391 * @see lock()
392 */
393 void unlock();
394
395 /**
396 * Copies the contents a subresource in this texture to another texture. Texture format and size of the subresource
397 * must match.
398 *
399 * You are allowed to copy from a multisampled to non-multisampled surface, which will resolve the multisampled
400 * surface before copying.
401 *
402 * @param[in] target Texture that contains the destination subresource.
403 * @param[in] desc Structure used for customizing the copy operation.
404 * @param[in] commandBuffer Command buffer to queue the copy operation on. If null, main command buffer is
405 * used.
406 */
407 void copy(const SPtr<Texture>& target, const TEXTURE_COPY_DESC& desc = TEXTURE_COPY_DESC::DEFAULT,
408 const SPtr<CommandBuffer>& commandBuffer = nullptr);
409
410 /**
411 * Sets all the pixels of the specified face and mip level to the provided value.
412 *
413 * @param[in] value Color to clear the pixels to.
414 * @param[in] mipLevel Mip level to clear.
415 * @param[in] face Face (array index or cubemap face) to clear.
416 * @param[in] queueIdx Device queue to perform the write operation on. See @ref queuesDoc.
417 */
418 void clear(const Color& value, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 queueIdx = 0);
419
420 /**
421 * Reads data from the texture buffer into the provided buffer.
422 *
423 * @param[out] dest Previously allocated buffer to read data into.
424 * @param[in] mipLevel (optional) Mipmap level to read from.
425 * @param[in] face (optional) Texture face to read from.
426 * @param[in] deviceIdx Index of the device whose memory to read. If the buffer doesn't exist on this device,
427 * no data will be read.
428 * @param[in] queueIdx Device queue to perform the read operation on. See @ref queuesDoc.
429 */
430 void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
431 UINT32 queueIdx = 0);
432
433 /**
434 * Writes data from the provided buffer into the texture buffer.
435 *
436 * @param[in] src Buffer to retrieve the data from.
437 * @param[in] mipLevel (optional) Mipmap level to write into.
438 * @param[in] face (optional) Texture face to write into.
439 * @param[in] discardWholeBuffer (optional) If true any existing texture data will be discard. This can improve
440 * performance of the write operation.
441 * @param[in] queueIdx Device queue to perform the write operation on. See @ref queuesDoc.
442 */
443 void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false,
444 UINT32 queueIdx = 0);
445
446 /** Returns properties that contain information about the texture. */
447 const TextureProperties& getProperties() const { return mProperties; }
448
449 /************************************************************************/
450 /* STATICS */
451 /************************************************************************/
452
453 /**
454 * @copydoc bs::Texture::create(const TEXTURE_DESC&)
455 * @param[in] deviceMask Mask that determines on which GPU devices should the object be created on.
456 */
457 static SPtr<Texture> create(const TEXTURE_DESC& desc, GpuDeviceFlags deviceMask = GDF_DEFAULT);
458
459 /**
460 * @copydoc bs::Texture::create(const SPtr<PixelData>&, int, bool)
461 * @param[in] deviceMask Mask that determines on which GPU devices should the object be created on.
462 */
463 static SPtr<Texture> create(const SPtr<PixelData>& pixelData, int usage = TU_DEFAULT,
464 bool hwGammaCorrection = false, GpuDeviceFlags deviceMask = GDF_DEFAULT);
465
466 /************************************************************************/
467 /* TEXTURE VIEW */
468 /************************************************************************/
469
470 /**
471 * Requests a texture view for the specified mip and array ranges. Returns an existing view of one for the specified
472 * ranges already exists, otherwise creates a new one. You must release all views by calling releaseView() when done.
473 *
474 * @note Core thread only.
475 */
476 SPtr<TextureView> requestView(UINT32 mostDetailMip, UINT32 numMips, UINT32 firstArraySlice, UINT32 numArraySlices,
477 GpuViewUsage usage);
478
479 /** Returns a plain white texture. */
480 static SPtr<Texture> WHITE;
481
482 /** Returns a plain black texture. */
483 static SPtr<Texture> BLACK;
484
485 /** Returns a plain normal map texture with normal pointing up (in Y direction). */
486 static SPtr<Texture> NORMAL;
487 protected:
488 /** @copydoc lock */
489 virtual PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
490 UINT32 queueIdx = 0) = 0;
491
492 /** @copydoc unlock */
493 virtual void unlockImpl() = 0;
494
495 /** @copydoc copy */
496 virtual void copyImpl(const SPtr<Texture>& target, const TEXTURE_COPY_DESC& desc,
497 const SPtr<CommandBuffer>& commandBuffer) = 0;
498
499 /** @copydoc readData */
500 virtual void readDataImpl(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
501 UINT32 queueIdx = 0) = 0;
502
503 /** @copydoc writeData */
504 virtual void writeDataImpl(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0,
505 bool discardWholeBuffer = false, UINT32 queueIdx = 0) = 0;
506
507 /** @copydoc clear */
508 virtual void clearImpl(const Color& value, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 queueIdx = 0);
509
510 /************************************************************************/
511 /* TEXTURE VIEW */
512 /************************************************************************/
513
514 /** Creates a view of a specific subresource in a texture. */
515 virtual SPtr<TextureView> createView(const TEXTURE_VIEW_DESC& desc);
516
517 /** Releases all internal texture view references. */
518 void clearBufferViews();
519
520 UnorderedMap<TEXTURE_VIEW_DESC, SPtr<TextureView>, TextureView::HashFunction, TextureView::EqualFunction> mTextureViews;
521 TextureProperties mProperties;
522 SPtr<PixelData> mInitData;
523 };
524
525 /** @} */
526 }
527}