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/BsRenderAPI.h"
4
5#include "CoreThread/BsCoreThread.h"
6#include "RenderAPI/BsViewport.h"
7#include "RenderAPI/BsRenderTarget.h"
8#include "RenderAPI/BsRenderWindow.h"
9#include "Mesh/BsMesh.h"
10#include "RenderAPI/BsGpuParams.h"
11#include "RenderAPI/BsDepthStencilState.h"
12#include "RenderAPI/BsRasterizerState.h"
13#include "RenderAPI/BsGpuBuffer.h"
14#include "RenderAPI/BsGpuPipelineState.h"
15
16using namespace std::placeholders;
17
18namespace bs
19{
20 void RenderAPI::setGpuParams(const SPtr<GpuParams>& gpuParams)
21 {
22 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setGpuParams, ct::RenderAPI::instancePtr(), gpuParams->getCore(),
23 nullptr));
24 }
25
26 void RenderAPI::setGraphicsPipeline(const SPtr<GraphicsPipelineState>& pipelineState)
27 {
28 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setGraphicsPipeline, ct::RenderAPI::instancePtr(),
29 pipelineState->getCore(), nullptr));
30 }
31
32 void RenderAPI::setComputePipeline(const SPtr<ComputePipelineState>& pipelineState)
33 {
34 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setComputePipeline, ct::RenderAPI::instancePtr(),
35 pipelineState->getCore(), nullptr));
36 }
37
38 void RenderAPI::setVertexBuffers(UINT32 index, const Vector<SPtr<VertexBuffer>>& buffers)
39 {
40 Vector<SPtr<ct::VertexBuffer>> coreBuffers(buffers.size());
41 for (UINT32 i = 0; i < (UINT32)buffers.size(); i++)
42 coreBuffers[i] = buffers[i] != nullptr ? buffers[i]->getCore() : nullptr;
43
44 std::function<void(ct::RenderAPI*, UINT32, const Vector<SPtr<ct::VertexBuffer>>&)> resizeFunc =
45 [](ct::RenderAPI* rs, UINT32 idx, const Vector<SPtr<ct::VertexBuffer>>& _buffers)
46 {
47 rs->setVertexBuffers(idx, (SPtr<ct::VertexBuffer>*)_buffers.data(), (UINT32)_buffers.size());
48 };
49
50 gCoreThread().queueCommand(std::bind(resizeFunc, ct::RenderAPI::instancePtr(), index, coreBuffers));
51 }
52
53 void RenderAPI::setIndexBuffer(const SPtr<IndexBuffer>& buffer)
54 {
55 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setIndexBuffer, ct::RenderAPI::instancePtr(), buffer->getCore(),
56 nullptr));
57 }
58
59 void RenderAPI::setVertexDeclaration(const SPtr<VertexDeclaration>& vertexDeclaration)
60 {
61 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setVertexDeclaration, ct::RenderAPI::instancePtr(),
62 vertexDeclaration->getCore(), nullptr));
63 }
64
65 void RenderAPI::setViewport(const Rect2& vp)
66 {
67 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setViewport, ct::RenderAPI::instancePtr(), vp, nullptr));
68 }
69
70 void RenderAPI::setStencilRef(UINT32 value)
71 {
72 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setStencilRef, ct::RenderAPI::instancePtr(), value, nullptr));
73 }
74
75 void RenderAPI::setDrawOperation(DrawOperationType op)
76 {
77 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setDrawOperation, ct::RenderAPI::instancePtr(), op,
78 nullptr));
79 }
80
81 void RenderAPI::setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
82 {
83 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setScissorRect, ct::RenderAPI::instancePtr(), left, top, right, bottom,
84 nullptr));
85 }
86
87 void RenderAPI::setRenderTarget(const SPtr<RenderTarget>& target, UINT32 readOnlyFlags,
88 RenderSurfaceMask loadMask)
89 {
90 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::setRenderTarget,
91 ct::RenderAPI::instancePtr(), target->getCore(), readOnlyFlags, loadMask, nullptr));
92 }
93
94 void RenderAPI::clearRenderTarget(UINT32 buffers, const Color& color, float depth,
95 UINT16 stencil, UINT8 targetMask)
96 {
97 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::clearRenderTarget, ct::RenderAPI::instancePtr(), buffers, color,
98 depth, stencil, targetMask, nullptr));
99 }
100
101 void RenderAPI::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil,
102 UINT8 targetMask)
103 {
104 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::clearViewport, ct::RenderAPI::instancePtr(), buffers, color, depth,
105 stencil, targetMask, nullptr));
106 }
107
108 void RenderAPI::swapBuffers(const SPtr<RenderTarget>& target)
109 {
110 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::swapBuffers, ct::RenderAPI::instancePtr(), target->getCore(), 1));
111 }
112
113 void RenderAPI::draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount)
114 {
115 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::draw, ct::RenderAPI::instancePtr(), vertexOffset,
116 vertexCount, instanceCount, nullptr));
117 }
118
119 void RenderAPI::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset,
120 UINT32 vertexCount, UINT32 instanceCount)
121 {
122 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::drawIndexed, ct::RenderAPI::instancePtr(), startIndex, indexCount,
123 vertexOffset, vertexCount, instanceCount, nullptr));
124 }
125
126 void RenderAPI::dispatchCompute(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ)
127 {
128 gCoreThread().queueCommand(std::bind(&ct::RenderAPI::dispatchCompute, ct::RenderAPI::instancePtr(), numGroupsX,
129 numGroupsY, numGroupsZ, nullptr));
130 }
131
132 const VideoModeInfo& RenderAPI::getVideoModeInfo()
133 {
134 return ct::RenderAPI::instance().getVideoModeInfo();
135 }
136
137 void RenderAPI::convertProjectionMatrix(const Matrix4& matrix, Matrix4& dest)
138 {
139 ct::RenderAPI::instance().convertProjectionMatrix(matrix, dest);
140 }
141
142 namespace ct
143 {
144 RenderAPI::RenderAPI()
145 : mCurrentCapabilities(nullptr), mNumDevices(0)
146 {
147 }
148
149 RenderAPI::~RenderAPI()
150 {
151 // Base classes need to call virtual destroy_internal method instead of a destructor
152
153 bs_deleteN(mCurrentCapabilities, mNumDevices);
154 mCurrentCapabilities = nullptr;
155 }
156
157 SPtr<bs::RenderWindow> RenderAPI::initialize(const RENDER_WINDOW_DESC& primaryWindowDesc)
158 {
159 gCoreThread().queueCommand(std::bind((void(RenderAPI::*)())&RenderAPI::initialize, this),
160 CTQF_InternalQueue | CTQF_BlockUntilComplete);
161
162 RENDER_WINDOW_DESC windowDesc = primaryWindowDesc;
163 SPtr<bs::RenderWindow> renderWindow = bs::RenderWindow::create(windowDesc, nullptr);
164
165 // Make sure render window initialization is submitted to the internal queue
166 gCoreThread().submitAll();
167
168 gCoreThread().queueCommand(std::bind(&RenderAPI::initializeWithWindow, this, renderWindow->getCore()),
169 CTQF_InternalQueue | CTQF_BlockUntilComplete);
170
171 return renderWindow;
172 }
173
174 void RenderAPI::initialize()
175 {
176 // Do nothing
177 }
178
179 void RenderAPI::initializeWithWindow(const SPtr<RenderWindow>& primaryWindow)
180 {
181 THROW_IF_NOT_CORE_THREAD;
182 }
183
184 void RenderAPI::destroy()
185 {
186 gCoreThread().queueCommand(std::bind(&RenderAPI::destroyCore, this));
187 gCoreThread().submitAll(true);
188 }
189
190 void RenderAPI::destroyCore()
191 {
192 mActiveRenderTarget = nullptr;
193 }
194
195 const RenderAPICapabilities& RenderAPI::getCapabilities(UINT32 deviceIdx) const
196 {
197 if(deviceIdx >= mNumDevices)
198 {
199 LOGWRN("Invalid device index provided: " + toString(deviceIdx) + ". Valid range is: [0, " + toString(mNumDevices) + ").");
200 return mCurrentCapabilities[0];
201 }
202
203 return mCurrentCapabilities[deviceIdx];
204 }
205
206 UINT32 RenderAPI::vertexCountToPrimCount(DrawOperationType type, UINT32 elementCount)
207 {
208 UINT32 primCount = 0;
209 switch (type)
210 {
211 case DOT_POINT_LIST:
212 primCount = elementCount;
213 break;
214
215 case DOT_LINE_LIST:
216 primCount = elementCount / 2;
217 break;
218
219 case DOT_LINE_STRIP:
220 primCount = elementCount - 1;
221 break;
222
223 case DOT_TRIANGLE_LIST:
224 primCount = elementCount / 3;
225 break;
226
227 case DOT_TRIANGLE_STRIP:
228 primCount = elementCount - 2;
229 break;
230
231 case DOT_TRIANGLE_FAN:
232 primCount = elementCount - 2;
233 break;
234 }
235
236 return primCount;
237 }
238 }
239}