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#include "BsCorePrerequisites.h"
5#include "RenderAPI/BsSamplerState.h"
6#include "CoreThread/BsCommandQueue.h"
7#include "RenderAPI/BsRenderAPICapabilities.h"
8#include "RenderAPI/BsRenderTarget.h"
9#include "RenderAPI/BsRenderTexture.h"
10#include "RenderAPI/BsRenderWindow.h"
11#include "RenderAPI/BsGpuProgram.h"
12#include "RenderAPI/BsVertexDeclaration.h"
13#include "Math/BsPlane.h"
14#include "Utility/BsModule.h"
15#include "Utility/BsEvent.h"
16
17namespace bs
18{
19 class RenderAPIManager;
20
21 /** @addtogroup RenderAPI
22 * @{
23 */
24
25 /**
26 * Provides access to ct::RenderAPI from the simulation thread. All the commands get queued on the core thread queue
27 * for the calling thread.
28 *
29 * @see ct::RenderAPI
30 *
31 * @note Sim thread only.
32 */
33 class BS_CORE_EXPORT RenderAPI
34 {
35 public:
36 /**
37 * @see ct::RenderAPI::setGpuParams()
38 *
39 * @note This is an @ref asyncMethod "asynchronous method".
40 */
41 static void setGpuParams(const SPtr<GpuParams>& gpuParams);
42
43 /**
44 * @see ct::RenderAPI::setGraphicsPipeline()
45 *
46 * @note This is an @ref asyncMethod "asynchronous method".
47 */
48 static void setGraphicsPipeline(const SPtr<GraphicsPipelineState>& pipelineState);
49
50 /**
51 * @see ct::RenderAPI::setComputePipeline()
52 *
53 * @note This is an @ref asyncMethod "asynchronous method".
54 */
55 static void setComputePipeline(const SPtr<ComputePipelineState>& pipelineState);
56
57 /**
58 * @see ct::RenderAPI::setVertexBuffers()
59 *
60 * @note This is an @ref asyncMethod "asynchronous method".
61 */
62 static void setVertexBuffers(UINT32 index, const Vector<SPtr<VertexBuffer>>& buffers);
63
64 /**
65 * @see ct::RenderAPI::setIndexBuffer()
66 *
67 * @note This is an @ref asyncMethod "asynchronous method".
68 */
69 static void setIndexBuffer(const SPtr<IndexBuffer>& buffer);
70
71 /**
72 * @see ct::RenderAPI::setVertexDeclaration()
73 *
74 * @note This is an @ref asyncMethod "asynchronous method".
75 */
76 static void setVertexDeclaration(const SPtr<VertexDeclaration>& vertexDeclaration);
77
78 /**
79 * @see ct::RenderAPI::setViewport()
80 *
81 * @note This is an @ref asyncMethod "asynchronous method".
82 */
83 static void setViewport(const Rect2& area);
84
85 /**
86 * @see ct::RenderAPI::setStencilRef()
87 *
88 * @note This is an @ref asyncMethod "asynchronous method".
89 */
90 static void setStencilRef(UINT32 value);
91
92 /**
93 * @see ct::RenderAPI::setDrawOperation()
94 *
95 * @note This is an @ref asyncMethod "asynchronous method".
96 */
97 static void setDrawOperation(DrawOperationType op);
98
99 /**
100 * @see ct::RenderAPI::setScissorRect()
101 *
102 * @note This is an @ref asyncMethod "asynchronous method".
103 */
104 static void setScissorRect(UINT32 left = 0, UINT32 top = 0, UINT32 right = 800, UINT32 bottom = 600);
105
106 /**
107 * @see ct::RenderAPI::setRenderTarget()
108 *
109 * @note This is an @ref asyncMethod "asynchronous method".
110 */
111 static void setRenderTarget(const SPtr<RenderTarget>& target, UINT32 readOnlyFlags = 0,
112 RenderSurfaceMask loadMask = RT_NONE);
113
114 /**
115 * @see ct::RenderAPI::clearRenderTarget()
116 *
117 * @note This is an @ref asyncMethod "asynchronous method".
118 */
119 static void clearRenderTarget(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f,
120 UINT16 stencil = 0, UINT8 targetMask = 0xFF);
121
122 /**
123 * @see ct::RenderAPI::clearViewport()
124 *
125 * @note This is an @ref asyncMethod "asynchronous method".
126 */
127 static void clearViewport(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f, UINT16 stencil = 0,
128 UINT8 targetMask = 0xFF);
129
130 /**
131 * @see ct::RenderAPI::swapBuffers()
132 *
133 * @note This is an @ref asyncMethod "asynchronous method".
134 */
135 static void swapBuffers(const SPtr<RenderTarget>& target);
136
137 /**
138 * @see ct::RenderAPI::draw()
139 *
140 * @note This is an @ref asyncMethod "asynchronous method".
141 */
142 static void draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount = 0);
143
144 /**
145 * @see ct::RenderAPI::drawIndexed()
146 *
147 * @note This is an @ref asyncMethod "asynchronous method".
148 */
149 static void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount,
150 UINT32 instanceCount = 0);
151
152 /**
153 * @see ct::RenderAPI::dispatchCompute()
154 *
155 * @note This is an @ref asyncMethod "asynchronous method".
156 */
157 static void dispatchCompute(UINT32 numGroupsX, UINT32 numGroupsY = 1, UINT32 numGroupsZ = 1);
158
159 /** @copydoc ct::RenderAPI::getVideoModeInfo */
160 static const VideoModeInfo& getVideoModeInfo();
161
162 /** @copydoc ct::RenderAPI::convertProjectionMatrix */
163 static void convertProjectionMatrix(const Matrix4& matrix, Matrix4& dest);
164 };
165
166 /** @} */
167
168 namespace ct
169 {
170 /** @addtogroup RenderAPI-Internal
171 * @{
172 */
173
174 /**
175 * Provides low-level API access to rendering commands (internally wrapping DirectX/OpenGL/Vulkan or similar).
176 *
177 * Methods that accept a CommandBuffer parameter get queued in the provided command buffer, and don't get executed until
178 * executeCommands() method is called. User is allowed to populate command buffers from non-core threads, but they all
179 * must get executed from the core thread.
180 *
181 * If a command buffer is not provivided to such methods, they execute immediately. Without a command buffer the methods
182 * are only allowed to be called from the core thread.
183 *
184 * @note Accessible on any thread for methods accepting a CommandBuffer. Otherwise core thread unless specifically
185 * noted otherwise on per-method basis.
186 */
187 class BS_CORE_EXPORT RenderAPI : public Module<RenderAPI>
188 {
189 public:
190 RenderAPI();
191 virtual ~RenderAPI();
192
193 /**
194 * Returns the name of the rendering system.
195 *
196 * @note Thread safe.
197 */
198 virtual const StringID& getName() const = 0;
199
200 /**
201 * Applies a set of parameters that control execution of all currently bound GPU programs. These are the uniforms
202 * like textures, samplers, or uniform buffers. Caller is expected to ensure the provided parameters actually
203 * match the currently bound programs.
204 */
205 virtual void setGpuParams(const SPtr<GpuParams>& gpuParams,
206 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
207
208 /**
209 * Sets a pipeline state that controls how will subsequent draw commands render primitives.
210 *
211 * @param[in] pipelineState Pipeline state to bind, or null to unbind.
212 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
213 * is executed immediately. Otherwise it is executed when executeCommands() is
214 * called. Buffer must support graphics operations.
215 *
216 * @see GraphicsPipelineState
217 */
218 virtual void setGraphicsPipeline(const SPtr<GraphicsPipelineState>& pipelineState,
219 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
220
221 /**
222 * Sets a pipeline state that controls how will subsequent dispatch commands execute.
223 *
224 * @param[in] pipelineState Pipeline state to bind, or null to unbind.
225 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
226 * is executed immediately. Otherwise it is executed when executeCommands() is
227 * called. Buffer must support graphics operations.
228 */
229 virtual void setComputePipeline(const SPtr<ComputePipelineState>& pipelineState,
230 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
231
232 /**
233 * Sets the active viewport that will be used for all render operations.
234 *
235 * @param[in] area Area of the viewport, in normalized ([0,1] range) coordinates.
236 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
237 * is executed immediately. Otherwise it is executed when executeCommands() is called.
238 * Buffer must support graphics operations.
239 */
240 virtual void setViewport(const Rect2& area, const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
241
242 /**
243 * Allows you to set up a region in which rendering can take place. Coordinates are in pixels. No rendering will be
244 * done to render target pixels outside of the provided region.
245 *
246 * @param[in] left Left border of the scissor rectangle, in pixels.
247 * @param[in] top Top border of the scissor rectangle, in pixels.
248 * @param[in] right Right border of the scissor rectangle, in pixels.
249 * @param[in] bottom Bottom border of the scissor rectangle, in pixels.
250 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
251 * is executed immediately. Otherwise it is executed when executeCommands() is called.
252 * Buffer must support graphics operations.
253 */
254 virtual void setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom,
255 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
256
257 /**
258 * Sets a reference value that will be used for stencil compare operations.
259 *
260 * @param[in] value Reference value to set.
261 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
262 * is executed immediately. Otherwise it is executed when executeCommands() is called.
263 * Buffer must support graphics operations.
264 */
265 virtual void setStencilRef(UINT32 value, const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
266
267 /**
268 * Sets the provided vertex buffers starting at the specified source index. Set buffer to nullptr to clear the
269 * buffer at the specified index.
270 *
271 * @param[in] index Index at which to start binding the vertex buffers.
272 * @param[in] buffers A list of buffers to bind to the pipeline.
273 * @param[in] numBuffers Number of buffers in the @p buffers list.
274 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
275 * is executed immediately. Otherwise it is executed when executeCommands() is called.
276 * Buffer must support graphics operations.
277 */
278 virtual void setVertexBuffers(UINT32 index, SPtr<VertexBuffer>* buffers, UINT32 numBuffers,
279 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
280
281 /**
282 * Sets an index buffer to use when drawing. Indices in an index buffer reference vertices in the vertex buffer,
283 * which increases cache coherency and reduces the size of vertex buffers by eliminating duplicate data.
284 *
285 * @param[in] buffer Index buffer to bind, null to unbind.
286 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
287 * is executed immediately. Otherwise it is executed when executeCommands() is called.
288 * Buffer must support graphics operations.
289 */
290 virtual void setIndexBuffer(const SPtr<IndexBuffer>& buffer,
291 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
292
293 /**
294 * Sets the vertex declaration to use when drawing. Vertex declaration is used to decode contents of a single
295 * vertex in a vertex buffer.
296 *
297 * @param[in] vertexDeclaration Vertex declaration to bind.
298 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
299 * is executed immediately. Otherwise it is executed when executeCommands() is
300 * called. Buffer must support graphics operations.
301 */
302 virtual void setVertexDeclaration(const SPtr<VertexDeclaration>& vertexDeclaration,
303 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
304
305 /**
306 * Sets the draw operation that determines how to interpret the elements of the index or vertex buffers.
307 *
308 * @param[in] op Draw operation to enable.
309 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
310 * is executed immediately. Otherwise it is executed when executeCommands() is called.
311 * Buffer must support graphics operations.
312 */
313 virtual void setDrawOperation(DrawOperationType op,
314 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
315
316 /**
317 * Draw an object based on currently bound GPU programs, vertex declaration and vertex buffers. Draws directly from
318 * the vertex buffer without using indices.
319 *
320 * @param[in] vertexOffset Offset into the currently bound vertex buffer to start drawing from.
321 * @param[in] vertexCount Number of vertices to draw.
322 * @param[in] instanceCount Number of times to draw the provided geometry, each time with an (optionally)
323 * separate per-instance data.
324 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
325 * is executed immediately. Otherwise it is executed when executeCommands() is called.
326 * Buffer must support graphics operations.
327 */
328 virtual void draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount = 0,
329 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
330
331 /**
332 * Draw an object based on currently bound GPU programs, vertex declaration, vertex and index buffers.
333 *
334 * @param[in] startIndex Offset into the currently bound index buffer to start drawing from.
335 * @param[in] indexCount Number of indices to draw.
336 * @param[in] vertexOffset Offset to apply to each vertex index.
337 * @param[in] vertexCount Number of vertices to draw.
338 * @param[in] instanceCount Number of times to draw the provided geometry, each time with an (optionally)
339 * separate per-instance data.
340 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
341 * is executed immediately. Otherwise it is executed when executeCommands() is called.
342 * Buffer must support graphics operations.
343 */
344 virtual void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount,
345 UINT32 instanceCount = 0, const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
346
347 /**
348 * Executes the currently bound compute shader.
349 *
350 * @param[in] numGroupsX Number of groups to start in the X direction. Must be in range [1, 65535].
351 * @param[in] numGroupsY Number of groups to start in the Y direction. Must be in range [1, 65535].
352 * @param[in] numGroupsZ Number of groups to start in the Z direction. Must be in range [1, 64].
353 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
354 * is executed immediately. Otherwise it is executed when executeCommands() is called.
355 * Buffer must support compute or graphics operations.
356 */
357 virtual void dispatchCompute(UINT32 numGroupsX, UINT32 numGroupsY = 1, UINT32 numGroupsZ = 1,
358 const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
359
360 /**
361 * Swap the front and back buffer of the specified render target.
362 *
363 * @param[in] target Render target to perform the buffer swap on.
364 * @param[in] syncMask Optional synchronization mask that determines for which queues should the system wait
365 * before performing the swap buffer operation. By default the system waits for all queues.
366 * However if certain queues are performing non-rendering operations, or operations not
367 * related to the provided render target, you can exclude them from the sync mask for
368 * potentially better performance. You can use CommandSyncMask to generate a valid sync mask.
369 */
370 virtual void swapBuffers(const SPtr<RenderTarget>& target, UINT32 syncMask = 0xFFFFFFFF) = 0;
371
372 /**
373 * Change the render target into which we want to draw.
374 *
375 * @param[in] target Render target to draw to.
376 * @param[in] readOnlyFlags Combination of one or more elements of FrameBufferType denoting which buffers
377 * will be bound for read-only operations. This is useful for depth or stencil
378 * buffers which need to be bound both for depth/stencil tests, as well as
379 * shader reads.
380 * @param[in] loadMask Determines which render target surfaces will have their current contents
381 * preserved. By default when a render target is bound its contents will be
382 * lost. You might need to preserve contents if you need to perform blending
383 * or similar operations with the existing contents of the render target.
384 *
385 * Use the mask to select exactly which surfaces of the render target need
386 * their contents preserved.
387 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
388 * is executed immediately. Otherwise it is executed when executeCommands() is
389 * called. Buffer must support graphics operations.
390 */
391 virtual void setRenderTarget(const SPtr<RenderTarget>& target, UINT32 readOnlyFlags = 0,
392 RenderSurfaceMask loadMask = RT_NONE, const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
393
394 /**
395 * Clears the currently active render target.
396 *
397 * @param[in] buffers Combination of one or more elements of FrameBufferType denoting which buffers are
398 * to be cleared.
399 * @param[in] color The color to clear the color buffer with, if enabled.
400 * @param[in] depth The value to initialize the depth buffer with, if enabled.
401 * @param[in] stencil The value to initialize the stencil buffer with, if enabled.
402 * @param[in] targetMask In case multiple render targets are bound, this allows you to control which ones to
403 * clear (0x01 first, 0x02 second, 0x04 third, etc., and combinations).
404 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
405 * is executed immediately. Otherwise it is executed when executeCommands() is called.
406 * Buffer must support graphics operations.
407 */
408 virtual void clearRenderTarget(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f,
409 UINT16 stencil = 0, UINT8 targetMask = 0xFF, const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
410
411 /**
412 * Clears the currently active viewport (meaning it clears just a sub-area of a render-target that is covered by the
413 * viewport, as opposed to clearRenderTarget() which always clears the entire render target).
414 *
415 * @param[in] buffers Combination of one or more elements of FrameBufferType denoting which buffers are to
416 * be cleared.
417 * @param[in] color The color to clear the color buffer with, if enabled.
418 * @param[in] depth The value to initialize the depth buffer with, if enabled.
419 * @param[in] stencil The value to initialize the stencil buffer with, if enabled.
420 * @param[in] targetMask In case multiple render targets are bound, this allows you to control which ones to
421 * clear (0x01 first, 0x02 second, 0x04 third, etc., and combinations).
422 * @param[in] commandBuffer Optional command buffer to queue the operation on. If not provided operation
423 * is executed immediately. Otherwise it is executed when executeCommands() is called.
424 * Buffer must support graphics operations.
425 */
426 virtual void clearViewport(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f,
427 UINT16 stencil = 0, UINT8 targetMask = 0xFF, const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
428
429 /** Appends all commands from the provided secondary command buffer into the primary command buffer. */
430 virtual void addCommands(const SPtr<CommandBuffer>& commandBuffer, const SPtr<CommandBuffer>& secondary) = 0;
431
432 /**
433 * Executes all commands in the provided command buffer. Command buffer cannot be secondary.
434 *
435 * @param[in] commandBuffer Command buffer whose commands to execute. Set to null to submit the main command
436 * buffer.
437 * @param[in] syncMask Optional synchronization mask that determines if the submitted command buffer
438 * depends on any other command buffers. Use the CommandSyncMask class to generate
439 * a mask using existing command buffers.
440 *
441 * This mask is only relevant if your command buffers are executing on different
442 * hardware queues, and are somehow dependant. If they are executing on the same queue
443 * (default) then they will execute sequentially in the order they are submitted.
444 * Otherwise, if there is a dependency, you must make state it explicitly here.
445 *
446 * @note Core thread only.
447 */
448 virtual void submitCommandBuffer(const SPtr<CommandBuffer>& commandBuffer, UINT32 syncMask = 0xFFFFFFFF) = 0;
449
450 /**
451 * Gets the capabilities of a specific GPU.
452 *
453 * @param[in] deviceIdx Index of the device to get the capabilities for.
454 *
455 * @note Thread safe.
456 */
457 const RenderAPICapabilities& getCapabilities(UINT32 deviceIdx) const;
458
459 /** Returns the number of devices supported by this render API. */
460 UINT32 getNumDevices() const { return mNumDevices; }
461
462 /**
463 * Returns information about available output devices and their video modes.
464 *
465 * @note Thread safe.
466 */
467 const VideoModeInfo& getVideoModeInfo() const { return *mVideoModeInfo; }
468
469 /************************************************************************/
470 /* UTILITY METHODS */
471 /************************************************************************/
472
473 /**
474 * Contains a default matrix into a matrix suitable for use by this specific render system.
475 *
476 * @note Thread safe.
477 */
478 virtual void convertProjectionMatrix(const Matrix4& matrix, Matrix4& dest) = 0;
479
480 /**
481 * Generates a parameter block description and calculates per-parameter offsets for the provided gpu data
482 * parameters. The offsets are render API specific and correspond to std140 layout for OpenGL, and the default
483 * layout in DirectX.
484 *
485 * @param[in] name Name to assign the parameter block.
486 * @param[in] params List of parameters in the parameter block. Only name, type and array size fields need to be
487 * populated, the rest will be populated when the method returns. If a parameter is a struct
488 * then the elementSize field needs to be populated with the size of the struct in bytes.
489 * @return Descriptor for the parameter block holding the provided parameters as laid out by the
490 * default render API layout.
491 */
492 virtual GpuParamBlockDesc generateParamBlockDesc(const String& name, Vector<GpuParamDataDesc>& params) = 0;
493
494 /************************************************************************/
495 /* INTERNAL METHODS */
496 /************************************************************************/
497 protected:
498 /**
499 * Initializes the render API system and creates a primary render window.
500 *
501 * @note Sim thread only.
502 */
503 SPtr<bs::RenderWindow> initialize(const RENDER_WINDOW_DESC& primaryWindowDesc);
504
505 /** Initializes the render API system. Called before the primary render window is created. */
506 virtual void initialize();
507
508 /**
509 * Performs (optional) secondary initialization of the render API system. Called after the render window is
510 * created.
511 */
512 virtual void initializeWithWindow(const SPtr<RenderWindow>& primaryWindow);
513
514 /**
515 * Shuts down the render API system and cleans up all resources.
516 *
517 * @note Sim thread.
518 */
519 void destroy();
520
521 /** Performs render API system shutdown on the core thread. */
522 virtual void destroyCore();
523
524 /** Converts the number of vertices to number of primitives based on the specified draw operation. */
525 UINT32 vertexCountToPrimCount(DrawOperationType type, UINT32 elementCount);
526
527 /************************************************************************/
528 /* INTERNAL DATA */
529 /************************************************************************/
530 protected:
531 friend class bs::RenderAPIManager;
532
533 SPtr<RenderTarget> mActiveRenderTarget;
534
535 RenderAPICapabilities* mCurrentCapabilities;
536 UINT32 mNumDevices;
537 SPtr<VideoModeInfo> mVideoModeInfo;
538 };
539
540 /** Shorthand for RenderAPI::getCapabilities(). */
541 inline const RenderAPICapabilities& gCaps(UINT32 deviceIdx = 0)
542 {
543 return RenderAPI::instance().getCapabilities(deviceIdx);
544 }
545
546 /** @} */
547 }
548}