blob: 1f0ad7dde23639c4a74df6564d53f39ae5c3cead [file] [log] [blame]
Brandon Jonesc9610c52014-08-25 17:02:59 -07001//
2// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl.
8
9#include "libGLESv2/renderer/d3d/ProgramD3D.h"
10
11#include "common/utilities.h"
Brandon Jones18bd4102014-09-22 14:21:44 -070012#include "libGLESv2/Program.h"
Brandon Jonesc9610c52014-08-25 17:02:59 -070013#include "libGLESv2/ProgramBinary.h"
14#include "libGLESv2/renderer/Renderer.h"
15#include "libGLESv2/renderer/ShaderExecutable.h"
16#include "libGLESv2/renderer/d3d/DynamicHLSL.h"
Brandon Jones22502d52014-08-29 16:58:36 -070017#include "libGLESv2/renderer/d3d/ShaderD3D.h"
Brandon Jonesc9610c52014-08-25 17:02:59 -070018#include "libGLESv2/main.h"
19
20namespace rx
21{
22
23ProgramD3D::ProgramD3D(rx::Renderer *renderer)
24 : ProgramImpl(),
25 mRenderer(renderer),
26 mDynamicHLSL(NULL),
Brandon Jones22502d52014-08-29 16:58:36 -070027 mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
28 mPixelWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
Brandon Jones44151a92014-09-10 11:32:25 -070029 mUsesPointSize(false),
Brandon Jonesc9610c52014-08-25 17:02:59 -070030 mVertexUniformStorage(NULL),
Brandon Jones44151a92014-09-10 11:32:25 -070031 mFragmentUniformStorage(NULL),
32 mShaderVersion(100)
Brandon Jonesc9610c52014-08-25 17:02:59 -070033{
34 mDynamicHLSL = new rx::DynamicHLSL(renderer);
35}
36
37ProgramD3D::~ProgramD3D()
38{
39 reset();
40 SafeDelete(mDynamicHLSL);
41}
42
43ProgramD3D *ProgramD3D::makeProgramD3D(ProgramImpl *impl)
44{
45 ASSERT(HAS_DYNAMIC_TYPE(ProgramD3D*, impl));
46 return static_cast<ProgramD3D*>(impl);
47}
48
49const ProgramD3D *ProgramD3D::makeProgramD3D(const ProgramImpl *impl)
50{
51 ASSERT(HAS_DYNAMIC_TYPE(const ProgramD3D*, impl));
52 return static_cast<const ProgramD3D*>(impl);
53}
54
Brandon Jones44151a92014-09-10 11:32:25 -070055bool ProgramD3D::usesPointSize() const
56{
57 return mUsesPointSize;
58}
59
60bool ProgramD3D::usesPointSpriteEmulation() const
61{
62 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
63}
64
65bool ProgramD3D::usesGeometryShader() const
66{
67 return usesPointSpriteEmulation();
68}
69
Brandon Jones22502d52014-08-29 16:58:36 -070070bool ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
71{
Brandon Jones44151a92014-09-10 11:32:25 -070072 stream->readInt(&mShaderVersion);
73
Brandon Jones22502d52014-08-29 16:58:36 -070074 stream->readString(&mVertexHLSL);
75 stream->readInt(&mVertexWorkarounds);
76 stream->readString(&mPixelHLSL);
77 stream->readInt(&mPixelWorkarounds);
78 stream->readBool(&mUsesFragDepth);
Brandon Jones44151a92014-09-10 11:32:25 -070079 stream->readBool(&mUsesPointSize);
Brandon Jones22502d52014-08-29 16:58:36 -070080
81 const size_t pixelShaderKeySize = stream->readInt<unsigned int>();
82 mPixelShaderKey.resize(pixelShaderKeySize);
83 for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++)
84 {
85 stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].type);
86 stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].name);
87 stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].source);
88 stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex);
89 }
90
Brandon Jones18bd4102014-09-22 14:21:44 -070091 GUID binaryIdentifier = {0};
92 stream->readBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID));
93
94 GUID identifier = mRenderer->getAdapterIdentifier();
95 if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0)
96 {
97 infoLog.append("Invalid program binary.");
98 return false;
99 }
100
Brandon Jones22502d52014-08-29 16:58:36 -0700101 return true;
102}
103
104bool ProgramD3D::save(gl::BinaryOutputStream *stream)
105{
Brandon Jones44151a92014-09-10 11:32:25 -0700106 stream->writeInt(mShaderVersion);
107
Brandon Jones22502d52014-08-29 16:58:36 -0700108 stream->writeString(mVertexHLSL);
109 stream->writeInt(mVertexWorkarounds);
110 stream->writeString(mPixelHLSL);
111 stream->writeInt(mPixelWorkarounds);
112 stream->writeInt(mUsesFragDepth);
Brandon Jones44151a92014-09-10 11:32:25 -0700113 stream->writeInt(mUsesPointSize);
Brandon Jones22502d52014-08-29 16:58:36 -0700114
115 const std::vector<rx::PixelShaderOutputVariable> &pixelShaderKey = mPixelShaderKey;
116 stream->writeInt(pixelShaderKey.size());
117 for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++)
118 {
119 const rx::PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex];
120 stream->writeInt(variable.type);
121 stream->writeString(variable.name);
122 stream->writeString(variable.source);
123 stream->writeInt(variable.outputIndex);
124 }
125
Brandon Jones18bd4102014-09-22 14:21:44 -0700126 GUID binaryIdentifier = mRenderer->getAdapterIdentifier();
127 stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID));
128
Brandon Jones22502d52014-08-29 16:58:36 -0700129 return true;
130}
131
Brandon Jones18bd4102014-09-22 14:21:44 -0700132ShaderExecutable *ProgramD3D::getPixelExecutableForOutputLayout(gl::InfoLog &infoLog, const std::vector<GLenum> &outputSignature,
133 const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
134 bool separatedOutputBuffers)
Brandon Jones22502d52014-08-29 16:58:36 -0700135{
136 std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth,
137 outputSignature);
138
139 // Generate new pixel executable
Brandon Jones18bd4102014-09-22 14:21:44 -0700140 ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(infoLog, finalPixelHLSL.c_str(), rx::SHADER_PIXEL,
141 transformFeedbackLinkedVaryings, separatedOutputBuffers,
142 mPixelWorkarounds);
Brandon Jones22502d52014-08-29 16:58:36 -0700143
144 return pixelExecutable;
145}
146
Brandon Jones18bd4102014-09-22 14:21:44 -0700147ShaderExecutable *ProgramD3D::getVertexExecutableForInputLayout(gl::InfoLog &infoLog,
148 const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS],
149 const sh::Attribute shaderAttributes[],
150 const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
151 bool separatedOutputBuffers)
Brandon Jones22502d52014-08-29 16:58:36 -0700152{
153 // Generate new dynamic layout with attribute conversions
154 std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, shaderAttributes);
155
156 // Generate new vertex executable
Brandon Jones18bd4102014-09-22 14:21:44 -0700157 ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(infoLog, finalVertexHLSL.c_str(),
158 rx::SHADER_VERTEX,
159 transformFeedbackLinkedVaryings, separatedOutputBuffers,
160 mVertexWorkarounds);
Brandon Jones22502d52014-08-29 16:58:36 -0700161
162 return vertexExecutable;
163}
164
Brandon Jones18bd4102014-09-22 14:21:44 -0700165ShaderExecutable *ProgramD3D::getGeometryExecutable(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
166 const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
167 bool separatedOutputBuffers, int registers)
Brandon Jones44151a92014-09-10 11:32:25 -0700168{
Brandon Jones18bd4102014-09-22 14:21:44 -0700169 ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
170 ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
Brandon Jones44151a92014-09-10 11:32:25 -0700171
172 std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D);
173
Brandon Jones18bd4102014-09-22 14:21:44 -0700174 ShaderExecutable *geometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(),
175 rx::SHADER_GEOMETRY, transformFeedbackLinkedVaryings,
176 separatedOutputBuffers, rx::ANGLE_D3D_WORKAROUND_NONE);
Brandon Jones44151a92014-09-10 11:32:25 -0700177
178 return geometryExecutable;
179}
180
Brandon Jones18bd4102014-09-22 14:21:44 -0700181ShaderExecutable *ProgramD3D::loadExecutable(const void *function, size_t length, rx::ShaderType type,
182 const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
183 bool separatedOutputBuffers)
184{
185 return mRenderer->loadExecutable(function, length, type, transformFeedbackLinkedVaryings, separatedOutputBuffers);
186}
187
Brandon Jones22502d52014-08-29 16:58:36 -0700188bool ProgramD3D::link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
189 const std::vector<std::string> &transformFeedbackVaryings, int *registers,
190 std::vector<gl::LinkedVarying> *linkedVaryings, std::map<int, gl::VariableLocation> *outputVariables)
191{
192 rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
193 rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
194
195 mPixelHLSL = fragmentShaderD3D->getTranslatedSource();
196 mPixelWorkarounds = fragmentShaderD3D->getD3DWorkarounds();
197
198 mVertexHLSL = vertexShaderD3D->getTranslatedSource();
199 mVertexWorkarounds = vertexShaderD3D->getD3DWorkarounds();
Brandon Jones44151a92014-09-10 11:32:25 -0700200 mShaderVersion = vertexShaderD3D->getShaderVersion();
Brandon Jones22502d52014-08-29 16:58:36 -0700201
202 // Map the varyings to the register file
203 rx::VaryingPacking packing = { NULL };
204 *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings);
205
Geoff Langbdee2d52014-09-17 11:02:51 -0400206 if (*registers < 0)
Brandon Jones22502d52014-08-29 16:58:36 -0700207 {
208 return false;
209 }
210
211 if (!gl::ProgramBinary::linkVaryings(infoLog, fragmentShader, vertexShader))
212 {
213 return false;
214 }
215
216 if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, *registers, packing, mPixelHLSL, mVertexHLSL,
217 fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings,
218 linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth))
219 {
220 return false;
221 }
222
Brandon Jones44151a92014-09-10 11:32:25 -0700223 mUsesPointSize = vertexShaderD3D->usesPointSize();
224
Brandon Jones22502d52014-08-29 16:58:36 -0700225 return true;
226}
227
Brandon Jones44151a92014-09-10 11:32:25 -0700228void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const
229{
230 mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
231}
232
Brandon Jonesc9610c52014-08-25 17:02:59 -0700233void ProgramD3D::initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms)
234{
235 // Compute total default block size
236 unsigned int vertexRegisters = 0;
237 unsigned int fragmentRegisters = 0;
238 for (size_t uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
239 {
240 const gl::LinkedUniform &uniform = *uniforms[uniformIndex];
241
242 if (!gl::IsSampler(uniform.type))
243 {
244 if (uniform.isReferencedByVertexShader())
245 {
246 vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
247 }
248 if (uniform.isReferencedByFragmentShader())
249 {
250 fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
251 }
252 }
253 }
254
255 mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u);
256 mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u);
257}
258
Brandon Jones18bd4102014-09-22 14:21:44 -0700259gl::Error ProgramD3D::applyUniforms(const std::vector<gl::LinkedUniform*> &uniforms)
260{
261 return mRenderer->applyUniforms(*this, uniforms);
262}
263
264gl::Error ProgramD3D::applyUniformBuffers(const std::vector<gl::UniformBlock*> uniformBlocks, const std::vector<gl::Buffer*> boundBuffers,
265 const gl::Caps &caps)
266{
267 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
268 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
269
270 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
271 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
272
273 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size(); uniformBlockIndex++)
274 {
275 gl::UniformBlock *uniformBlock = uniformBlocks[uniformBlockIndex];
276 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
277
278 ASSERT(uniformBlock && uniformBuffer);
279
280 if (uniformBuffer->getSize() < uniformBlock->dataSize)
281 {
282 // undefined behaviour
283 return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small.");
284 }
285
286 // Unnecessary to apply an unreferenced standard or shared UBO
287 if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader())
288 {
289 continue;
290 }
291
292 if (uniformBlock->isReferencedByVertexShader())
293 {
294 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
295 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
296 ASSERT(registerIndex < caps.maxVertexUniformBlocks);
297 vertexUniformBuffers[registerIndex] = uniformBuffer;
298 }
299
300 if (uniformBlock->isReferencedByFragmentShader())
301 {
302 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
303 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
304 ASSERT(registerIndex < caps.maxFragmentUniformBlocks);
305 fragmentUniformBuffers[registerIndex] = uniformBuffer;
306 }
307 }
308
309 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
310}
311
312bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
313 unsigned int registerIndex, const gl::Caps &caps)
314{
315 if (shader == GL_VERTEX_SHADER)
316 {
317 uniformBlock->vsRegisterIndex = registerIndex;
318 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks)
319 {
320 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks);
321 return false;
322 }
323 }
324 else if (shader == GL_FRAGMENT_SHADER)
325 {
326 uniformBlock->psRegisterIndex = registerIndex;
327 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks)
328 {
329 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks);
330 return false;
331 }
332 }
333 else UNREACHABLE();
334
335 return true;
336}
337
338unsigned int ProgramD3D::getReservedUniformVectors(GLenum shader)
339{
340 if (shader == GL_VERTEX_SHADER)
341 {
342 return mRenderer->getReservedVertexUniformVectors();
343 }
344 else if (shader == GL_FRAGMENT_SHADER)
345 {
346 return mRenderer->getReservedFragmentUniformVectors();
347 }
348 else UNREACHABLE();
349
350 return 0;
351}
352
Brandon Jonesc9610c52014-08-25 17:02:59 -0700353void ProgramD3D::reset()
354{
Brandon Jones22502d52014-08-29 16:58:36 -0700355 mVertexHLSL.clear();
356 mVertexWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
Brandon Jones44151a92014-09-10 11:32:25 -0700357 mShaderVersion = 100;
Brandon Jones22502d52014-08-29 16:58:36 -0700358
359 mPixelHLSL.clear();
360 mPixelWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
361 mUsesFragDepth = false;
362 mPixelShaderKey.clear();
Brandon Jones44151a92014-09-10 11:32:25 -0700363 mUsesPointSize = false;
Brandon Jones22502d52014-08-29 16:58:36 -0700364
Brandon Jonesc9610c52014-08-25 17:02:59 -0700365 SafeDelete(mVertexUniformStorage);
366 SafeDelete(mFragmentUniformStorage);
367}
368
369}