1 //
2 // Copyright 2016 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 // ProgramVk.cpp:
7 // Implements the class methods for ProgramVk.
8 //
9
10 #include "libANGLE/renderer/vulkan/ProgramVk.h"
11
12 #include "common/debug.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/ProgramLinkedResources.h"
16 #include "libANGLE/renderer/glslang_wrapper_utils.h"
17 #include "libANGLE/renderer/renderer_utils.h"
18 #include "libANGLE/renderer/vulkan/BufferVk.h"
19 #include "libANGLE/renderer/vulkan/GlslangWrapperVk.h"
20 #include "libANGLE/renderer/vulkan/TextureVk.h"
21
22 namespace rx
23 {
24
25 namespace
26 {
27 // Identical to Std140 encoder in all aspects, except it ignores opaque uniform types.
28 class VulkanDefaultBlockEncoder : public sh::Std140BlockEncoder
29 {
30 public:
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)31 void advanceOffset(GLenum type,
32 const std::vector<unsigned int> &arraySizes,
33 bool isRowMajorMatrix,
34 int arrayStride,
35 int matrixStride) override
36 {
37 if (gl::IsOpaqueType(type))
38 {
39 return;
40 }
41
42 sh::Std140BlockEncoder::advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride,
43 matrixStride);
44 }
45 };
46
InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> & uniforms,sh::BlockLayoutMap * blockLayoutMapOut,size_t * blockSizeOut)47 void InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> &uniforms,
48 sh::BlockLayoutMap *blockLayoutMapOut,
49 size_t *blockSizeOut)
50 {
51 if (uniforms.empty())
52 {
53 *blockSizeOut = 0;
54 return;
55 }
56
57 VulkanDefaultBlockEncoder blockEncoder;
58 sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut);
59
60 size_t blockSize = blockEncoder.getCurrentOffset();
61
62 // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized.
63 if (blockSize == 0)
64 {
65 *blockSizeOut = 0;
66 return;
67 }
68
69 *blockSizeOut = blockSize;
70 return;
71 }
72
73 template <typename T>
UpdateDefaultUniformBlock(GLsizei count,uint32_t arrayIndex,int componentCount,const T * v,const sh::BlockMemberInfo & layoutInfo,angle::MemoryBuffer * uniformData)74 void UpdateDefaultUniformBlock(GLsizei count,
75 uint32_t arrayIndex,
76 int componentCount,
77 const T *v,
78 const sh::BlockMemberInfo &layoutInfo,
79 angle::MemoryBuffer *uniformData)
80 {
81 const int elementSize = sizeof(T) * componentCount;
82
83 uint8_t *dst = uniformData->data() + layoutInfo.offset;
84 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
85 {
86 uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride;
87 uint8_t *writePtr = dst + arrayOffset;
88 ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size());
89 memcpy(writePtr, v, elementSize * count);
90 }
91 else
92 {
93 // Have to respect the arrayStride between each element of the array.
94 int maxIndex = arrayIndex + count;
95 for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex;
96 writeIndex++, readIndex++)
97 {
98 const int arrayOffset = writeIndex * layoutInfo.arrayStride;
99 uint8_t *writePtr = dst + arrayOffset;
100 const T *readPtr = v + (readIndex * componentCount);
101 ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size());
102 memcpy(writePtr, readPtr, elementSize);
103 }
104 }
105 }
106
107 template <typename T>
ReadFromDefaultUniformBlock(int componentCount,uint32_t arrayIndex,T * dst,const sh::BlockMemberInfo & layoutInfo,const angle::MemoryBuffer * uniformData)108 void ReadFromDefaultUniformBlock(int componentCount,
109 uint32_t arrayIndex,
110 T *dst,
111 const sh::BlockMemberInfo &layoutInfo,
112 const angle::MemoryBuffer *uniformData)
113 {
114 ASSERT(layoutInfo.offset != -1);
115
116 const int elementSize = sizeof(T) * componentCount;
117 const uint8_t *source = uniformData->data() + layoutInfo.offset;
118
119 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
120 {
121 const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride;
122 memcpy(dst, readPtr, elementSize);
123 }
124 else
125 {
126 // Have to respect the arrayStride between each element of the array.
127 const int arrayOffset = arrayIndex * layoutInfo.arrayStride;
128 const uint8_t *readPtr = source + arrayOffset;
129 memcpy(dst, readPtr, elementSize);
130 }
131 }
132
133 class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
134 {
135 public:
makeEncoder()136 sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
137 };
138 } // anonymous namespace
139
140 // ProgramVk implementation.
ProgramVk(const gl::ProgramState & state)141 ProgramVk::ProgramVk(const gl::ProgramState &state) : ProgramImpl(state)
142 {
143 GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(&mGlslangProgramInterfaceInfo);
144 mExecutable.setProgram(this);
145 }
146
147 ProgramVk::~ProgramVk() = default;
148
destroy(const gl::Context * context)149 void ProgramVk::destroy(const gl::Context *context)
150 {
151 ContextVk *contextVk = vk::GetImpl(context);
152 reset(contextVk);
153 }
154
reset(ContextVk * contextVk)155 void ProgramVk::reset(ContextVk *contextVk)
156 {
157 mOriginalShaderInfo.release(contextVk);
158
159 GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(&mGlslangProgramInterfaceInfo);
160
161 mExecutable.reset(contextVk);
162 }
163
load(const gl::Context * context,gl::BinaryInputStream * stream,gl::InfoLog & infoLog)164 std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
165 gl::BinaryInputStream *stream,
166 gl::InfoLog &infoLog)
167 {
168 ContextVk *contextVk = vk::GetImpl(context);
169 gl::ShaderMap<size_t> requiredBufferSize;
170 requiredBufferSize.fill(0);
171
172 reset(contextVk);
173
174 mOriginalShaderInfo.load(stream);
175 mExecutable.load(stream);
176
177 // Deserializes the uniformLayout data of mDefaultUniformBlocks
178 for (gl::ShaderType shaderType : gl::AllShaderTypes())
179 {
180 const size_t uniformCount = stream->readInt<size_t>();
181 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
182 {
183 sh::BlockMemberInfo blockInfo;
184 gl::LoadBlockMemberInfo(stream, &blockInfo);
185 mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo);
186 }
187 }
188
189 // Deserializes required uniform block memory sizes
190 for (gl::ShaderType shaderType : gl::AllShaderTypes())
191 {
192 requiredBufferSize[shaderType] = stream->readInt<size_t>();
193 }
194
195 // Initialize and resize the mDefaultUniformBlocks' memory
196 angle::Result status = resizeUniformBlockMemory(contextVk, requiredBufferSize);
197 if (status != angle::Result::Continue)
198 {
199 return std::make_unique<LinkEventDone>(status);
200 }
201
202 status = mExecutable.createPipelineLayout(context, nullptr);
203 return std::make_unique<LinkEventDone>(status);
204 }
205
save(const gl::Context * context,gl::BinaryOutputStream * stream)206 void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream)
207 {
208 mOriginalShaderInfo.save(stream);
209 mExecutable.save(stream);
210
211 // Serializes the uniformLayout data of mDefaultUniformBlocks
212 for (gl::ShaderType shaderType : gl::AllShaderTypes())
213 {
214 const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size();
215 stream->writeInt(uniformCount);
216 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
217 {
218 sh::BlockMemberInfo &blockInfo =
219 mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex];
220 gl::WriteBlockMemberInfo(stream, blockInfo);
221 }
222 }
223
224 // Serializes required uniform block memory sizes
225 for (gl::ShaderType shaderType : gl::AllShaderTypes())
226 {
227 stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size());
228 }
229 }
230
setBinaryRetrievableHint(bool retrievable)231 void ProgramVk::setBinaryRetrievableHint(bool retrievable)
232 {
233 // Nothing to do here yet.
234 }
235
setSeparable(bool separable)236 void ProgramVk::setSeparable(bool separable)
237 {
238 // Nothing to do here yet.
239 }
240
241 // TODO: http://anglebug.com/3570: Move/Copy all of the necessary information into
242 // the ProgramExecutable, so this function can be removed.
fillProgramStateMap(gl::ShaderMap<const gl::ProgramState * > * programStatesOut)243 void ProgramVk::fillProgramStateMap(gl::ShaderMap<const gl::ProgramState *> *programStatesOut)
244 {
245 for (gl::ShaderType shaderType : gl::AllShaderTypes())
246 {
247 (*programStatesOut)[shaderType] = nullptr;
248 if (mState.getExecutable().hasLinkedShaderStage(shaderType))
249 {
250 (*programStatesOut)[shaderType] = &mState;
251 }
252 }
253 }
254
link(const gl::Context * context,const gl::ProgramLinkedResources & resources,gl::InfoLog & infoLog,const gl::ProgramMergedVaryings & mergedVaryings)255 std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
256 const gl::ProgramLinkedResources &resources,
257 gl::InfoLog &infoLog,
258 const gl::ProgramMergedVaryings &mergedVaryings)
259 {
260 ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::link");
261
262 ContextVk *contextVk = vk::GetImpl(context);
263 // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
264 // assignment done in that function.
265 linkResources(resources);
266
267 reset(contextVk);
268 mExecutable.clearVariableInfoMap();
269
270 // Gather variable info and compiled SPIR-V binaries.
271 gl::ShaderMap<const angle::spirv::Blob *> spirvBlobs;
272 GlslangWrapperVk::GetShaderCode(contextVk->getFeatures(), mState, resources,
273 &mGlslangProgramInterfaceInfo, &spirvBlobs,
274 &mExecutable.mVariableInfoMap);
275
276 // Compile the shaders.
277 angle::Result status = mOriginalShaderInfo.initShaders(
278 mState.getExecutable().getLinkedShaderStages(), spirvBlobs, mExecutable.mVariableInfoMap);
279 if (status != angle::Result::Continue)
280 {
281 return std::make_unique<LinkEventDone>(status);
282 }
283
284 status = initDefaultUniformBlocks(context);
285 if (status != angle::Result::Continue)
286 {
287 return std::make_unique<LinkEventDone>(status);
288 }
289
290 if (contextVk->getFeatures().enablePrecisionQualifiers.enabled)
291 {
292 mExecutable.resolvePrecisionMismatch(mergedVaryings);
293 }
294
295 // TODO(jie.a.chen@intel.com): Parallelize linking.
296 // http://crbug.com/849576
297 status = mExecutable.createPipelineLayout(context, nullptr);
298 return std::make_unique<LinkEventDone>(status);
299 }
300
linkResources(const gl::ProgramLinkedResources & resources)301 void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources)
302 {
303 Std140BlockLayoutEncoderFactory std140EncoderFactory;
304 gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory);
305
306 linker.linkResources(mState, resources);
307 }
308
initDefaultUniformBlocks(const gl::Context * glContext)309 angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
310 {
311 ContextVk *contextVk = vk::GetImpl(glContext);
312
313 // Process vertex and fragment uniforms into std140 packing.
314 gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
315 gl::ShaderMap<size_t> requiredBufferSize;
316 requiredBufferSize.fill(0);
317
318 generateUniformLayoutMapping(layoutMap, requiredBufferSize);
319 initDefaultUniformLayoutMapping(layoutMap);
320
321 // All uniform initializations are complete, now resize the buffers accordingly and return
322 return resizeUniformBlockMemory(contextVk, requiredBufferSize);
323 }
324
generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> & layoutMap,gl::ShaderMap<size_t> & requiredBufferSize)325 void ProgramVk::generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
326 gl::ShaderMap<size_t> &requiredBufferSize)
327 {
328 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
329
330 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
331 {
332 gl::Shader *shader = mState.getAttachedShader(shaderType);
333
334 if (shader)
335 {
336 const std::vector<sh::ShaderVariable> &uniforms = shader->getUniforms();
337 InitDefaultUniformBlock(uniforms, &layoutMap[shaderType],
338 &requiredBufferSize[shaderType]);
339 }
340 }
341 }
342
initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> & layoutMap)343 void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap)
344 {
345 // Init the default block layout info.
346 const auto &uniforms = mState.getUniforms();
347 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
348
349 for (const gl::VariableLocation &location : mState.getUniformLocations())
350 {
351 gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
352
353 if (location.used() && !location.ignored)
354 {
355 const auto &uniform = uniforms[location.index];
356 if (uniform.isInDefaultBlock() && !uniform.isSampler() && !uniform.isImage() &&
357 !uniform.isFragmentInOut)
358 {
359 std::string uniformName = uniform.name;
360 if (uniform.isArray())
361 {
362 // Gets the uniform name without the [0] at the end.
363 uniformName = gl::StripLastArrayIndex(uniformName);
364 ASSERT(uniformName.size() != uniform.name.size());
365 }
366
367 bool found = false;
368
369 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
370 {
371 auto it = layoutMap[shaderType].find(uniformName);
372 if (it != layoutMap[shaderType].end())
373 {
374 found = true;
375 layoutInfo[shaderType] = it->second;
376 }
377 }
378
379 ASSERT(found);
380 }
381 }
382
383 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
384 {
385 mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]);
386 }
387 }
388 }
389
resizeUniformBlockMemory(ContextVk * contextVk,gl::ShaderMap<size_t> & requiredBufferSize)390 angle::Result ProgramVk::resizeUniformBlockMemory(ContextVk *contextVk,
391 gl::ShaderMap<size_t> &requiredBufferSize)
392 {
393 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
394
395 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
396 {
397 if (requiredBufferSize[shaderType] > 0)
398 {
399 if (!mDefaultUniformBlocks[shaderType].uniformData.resize(
400 requiredBufferSize[shaderType]))
401 {
402 ANGLE_VK_CHECK(contextVk, false, VK_ERROR_OUT_OF_HOST_MEMORY);
403 }
404
405 // Initialize uniform buffer memory to zero by default.
406 mDefaultUniformBlocks[shaderType].uniformData.fill(0);
407 mDefaultUniformBlocksDirty.set(shaderType);
408 }
409 }
410
411 return angle::Result::Continue;
412 }
413
validate(const gl::Caps & caps,gl::InfoLog * infoLog)414 GLboolean ProgramVk::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
415 {
416 // No-op. The spec is very vague about the behavior of validation.
417 return GL_TRUE;
418 }
419
420 template <typename T>
setUniformImpl(GLint location,GLsizei count,const T * v,GLenum entryPointType)421 void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType)
422 {
423 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
424 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
425 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
426
427 ASSERT(!linkedUniform.isSampler());
428
429 if (linkedUniform.typeInfo->type == entryPointType)
430 {
431 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
432 {
433 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
434 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
435
436 // Assume an offset of -1 means the block is unused.
437 if (layoutInfo.offset == -1)
438 {
439 continue;
440 }
441
442 const GLint componentCount = linkedUniform.typeInfo->componentCount;
443 UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo,
444 &uniformBlock.uniformData);
445 mDefaultUniformBlocksDirty.set(shaderType);
446 }
447 }
448 else
449 {
450 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
451 {
452 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
453 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
454
455 // Assume an offset of -1 means the block is unused.
456 if (layoutInfo.offset == -1)
457 {
458 continue;
459 }
460
461 const GLint componentCount = linkedUniform.typeInfo->componentCount;
462
463 ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType));
464
465 GLint initialArrayOffset =
466 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset;
467 for (GLint i = 0; i < count; i++)
468 {
469 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset;
470 GLint *dest =
471 reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset);
472 const T *source = v + i * componentCount;
473
474 for (int c = 0; c < componentCount; c++)
475 {
476 dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
477 }
478 }
479
480 mDefaultUniformBlocksDirty.set(shaderType);
481 }
482 }
483 }
484
485 template <typename T>
getUniformImpl(GLint location,T * v,GLenum entryPointType) const486 void ProgramVk::getUniformImpl(GLint location, T *v, GLenum entryPointType) const
487 {
488 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
489 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
490
491 ASSERT(!linkedUniform.isSampler() && !linkedUniform.isImage());
492
493 const gl::ShaderType shaderType = linkedUniform.getFirstShaderTypeWhereActive();
494 ASSERT(shaderType != gl::ShaderType::InvalidEnum);
495
496 const DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
497 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
498
499 ASSERT(linkedUniform.typeInfo->componentType == entryPointType ||
500 linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType));
501
502 if (gl::IsMatrixType(linkedUniform.type))
503 {
504 const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset +
505 (locationInfo.arrayIndex * layoutInfo.arrayStride);
506 GetMatrixUniform(linkedUniform.type, v, reinterpret_cast<const T *>(ptrToElement), false);
507 }
508 else
509 {
510 ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex,
511 v, layoutInfo, &uniformBlock.uniformData);
512 }
513 }
514
setUniform1fv(GLint location,GLsizei count,const GLfloat * v)515 void ProgramVk::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
516 {
517 setUniformImpl(location, count, v, GL_FLOAT);
518 }
519
setUniform2fv(GLint location,GLsizei count,const GLfloat * v)520 void ProgramVk::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
521 {
522 setUniformImpl(location, count, v, GL_FLOAT_VEC2);
523 }
524
setUniform3fv(GLint location,GLsizei count,const GLfloat * v)525 void ProgramVk::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
526 {
527 setUniformImpl(location, count, v, GL_FLOAT_VEC3);
528 }
529
setUniform4fv(GLint location,GLsizei count,const GLfloat * v)530 void ProgramVk::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
531 {
532 setUniformImpl(location, count, v, GL_FLOAT_VEC4);
533 }
534
setUniform1iv(GLint location,GLsizei count,const GLint * v)535 void ProgramVk::setUniform1iv(GLint location, GLsizei count, const GLint *v)
536 {
537 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
538 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
539 if (linkedUniform.isSampler())
540 {
541 // We could potentially cache some indexing here. For now this is a no-op since the mapping
542 // is handled entirely in ContextVk.
543 return;
544 }
545
546 setUniformImpl(location, count, v, GL_INT);
547 }
548
setUniform2iv(GLint location,GLsizei count,const GLint * v)549 void ProgramVk::setUniform2iv(GLint location, GLsizei count, const GLint *v)
550 {
551 setUniformImpl(location, count, v, GL_INT_VEC2);
552 }
553
setUniform3iv(GLint location,GLsizei count,const GLint * v)554 void ProgramVk::setUniform3iv(GLint location, GLsizei count, const GLint *v)
555 {
556 setUniformImpl(location, count, v, GL_INT_VEC3);
557 }
558
setUniform4iv(GLint location,GLsizei count,const GLint * v)559 void ProgramVk::setUniform4iv(GLint location, GLsizei count, const GLint *v)
560 {
561 setUniformImpl(location, count, v, GL_INT_VEC4);
562 }
563
setUniform1uiv(GLint location,GLsizei count,const GLuint * v)564 void ProgramVk::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
565 {
566 setUniformImpl(location, count, v, GL_UNSIGNED_INT);
567 }
568
setUniform2uiv(GLint location,GLsizei count,const GLuint * v)569 void ProgramVk::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
570 {
571 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2);
572 }
573
setUniform3uiv(GLint location,GLsizei count,const GLuint * v)574 void ProgramVk::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
575 {
576 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3);
577 }
578
setUniform4uiv(GLint location,GLsizei count,const GLuint * v)579 void ProgramVk::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
580 {
581 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4);
582 }
583
584 template <int cols, int rows>
setUniformMatrixfv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)585 void ProgramVk::setUniformMatrixfv(GLint location,
586 GLsizei count,
587 GLboolean transpose,
588 const GLfloat *value)
589 {
590 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
591 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
592 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
593
594 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
595 {
596 DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
597 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
598
599 // Assume an offset of -1 means the block is unused.
600 if (layoutInfo.offset == -1)
601 {
602 continue;
603 }
604
605 SetFloatUniformMatrixGLSL<cols, rows>::Run(
606 locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value,
607 uniformBlock.uniformData.data() + layoutInfo.offset);
608
609 mDefaultUniformBlocksDirty.set(shaderType);
610 }
611 }
612
setUniformMatrix2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)613 void ProgramVk::setUniformMatrix2fv(GLint location,
614 GLsizei count,
615 GLboolean transpose,
616 const GLfloat *value)
617 {
618 setUniformMatrixfv<2, 2>(location, count, transpose, value);
619 }
620
setUniformMatrix3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)621 void ProgramVk::setUniformMatrix3fv(GLint location,
622 GLsizei count,
623 GLboolean transpose,
624 const GLfloat *value)
625 {
626 setUniformMatrixfv<3, 3>(location, count, transpose, value);
627 }
628
setUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)629 void ProgramVk::setUniformMatrix4fv(GLint location,
630 GLsizei count,
631 GLboolean transpose,
632 const GLfloat *value)
633 {
634 setUniformMatrixfv<4, 4>(location, count, transpose, value);
635 }
636
setUniformMatrix2x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)637 void ProgramVk::setUniformMatrix2x3fv(GLint location,
638 GLsizei count,
639 GLboolean transpose,
640 const GLfloat *value)
641 {
642 setUniformMatrixfv<2, 3>(location, count, transpose, value);
643 }
644
setUniformMatrix3x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)645 void ProgramVk::setUniformMatrix3x2fv(GLint location,
646 GLsizei count,
647 GLboolean transpose,
648 const GLfloat *value)
649 {
650 setUniformMatrixfv<3, 2>(location, count, transpose, value);
651 }
652
setUniformMatrix2x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)653 void ProgramVk::setUniformMatrix2x4fv(GLint location,
654 GLsizei count,
655 GLboolean transpose,
656 const GLfloat *value)
657 {
658 setUniformMatrixfv<2, 4>(location, count, transpose, value);
659 }
660
setUniformMatrix4x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)661 void ProgramVk::setUniformMatrix4x2fv(GLint location,
662 GLsizei count,
663 GLboolean transpose,
664 const GLfloat *value)
665 {
666 setUniformMatrixfv<4, 2>(location, count, transpose, value);
667 }
668
setUniformMatrix3x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)669 void ProgramVk::setUniformMatrix3x4fv(GLint location,
670 GLsizei count,
671 GLboolean transpose,
672 const GLfloat *value)
673 {
674 setUniformMatrixfv<3, 4>(location, count, transpose, value);
675 }
676
setUniformMatrix4x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)677 void ProgramVk::setUniformMatrix4x3fv(GLint location,
678 GLsizei count,
679 GLboolean transpose,
680 const GLfloat *value)
681 {
682 setUniformMatrixfv<4, 3>(location, count, transpose, value);
683 }
684
getUniformfv(const gl::Context * context,GLint location,GLfloat * params) const685 void ProgramVk::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
686 {
687 getUniformImpl(location, params, GL_FLOAT);
688 }
689
getUniformiv(const gl::Context * context,GLint location,GLint * params) const690 void ProgramVk::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
691 {
692 getUniformImpl(location, params, GL_INT);
693 }
694
getUniformuiv(const gl::Context * context,GLint location,GLuint * params) const695 void ProgramVk::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
696 {
697 getUniformImpl(location, params, GL_UNSIGNED_INT);
698 }
699
calcUniformUpdateRequiredSpace(ContextVk * contextVk,const gl::ProgramExecutable & glExecutable,gl::ShaderMap<VkDeviceSize> & uniformOffsets) const700 size_t ProgramVk::calcUniformUpdateRequiredSpace(ContextVk *contextVk,
701 const gl::ProgramExecutable &glExecutable,
702 gl::ShaderMap<VkDeviceSize> &uniformOffsets) const
703 {
704 size_t requiredSpace = 0;
705 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
706 {
707 if (mDefaultUniformBlocksDirty[shaderType])
708 {
709 uniformOffsets[shaderType] = requiredSpace;
710 requiredSpace += getDefaultUniformAlignedSize(contextVk, shaderType);
711 }
712 }
713 return requiredSpace;
714 }
715
updateUniforms(ContextVk * contextVk)716 angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
717 {
718 ASSERT(dirtyUniforms());
719
720 bool anyNewBufferAllocated = false;
721 uint8_t *bufferData = nullptr;
722 VkDeviceSize bufferOffset = 0;
723 uint32_t offsetIndex = 0;
724 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
725 gl::ShaderMap<VkDeviceSize> offsets; // offset to the beginning of bufferData
726 size_t requiredSpace;
727
728 // We usually only update uniform data for shader stages that are actually dirty. But when the
729 // buffer for uniform data have switched, because all shader stages are using the same buffer,
730 // we then must update uniform data for all shader stages to keep all shader stages' uniform
731 // data in the same buffer.
732 requiredSpace = calcUniformUpdateRequiredSpace(contextVk, glExecutable, offsets);
733 ASSERT(requiredSpace > 0);
734
735 // Allocate space from dynamicBuffer. Always try to allocate from the current buffer first.
736 // If that failed, we deal with fall out and try again.
737 vk::DynamicBuffer *defaultUniformStorage = contextVk->getDefaultUniformStorage();
738 if (!defaultUniformStorage->allocateFromCurrentBuffer(requiredSpace, &bufferData,
739 &bufferOffset))
740 {
741 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
742 {
743 if (!mDefaultUniformBlocks[shaderType].uniformData.empty())
744 {
745 mDefaultUniformBlocksDirty.set(shaderType);
746 }
747 }
748
749 requiredSpace = calcUniformUpdateRequiredSpace(contextVk, glExecutable, offsets);
750 ANGLE_TRY(defaultUniformStorage->allocate(contextVk, requiredSpace, &bufferData, nullptr,
751 &bufferOffset, &anyNewBufferAllocated));
752 }
753
754 // Update buffer memory by immediate mapping. This immediate update only works once.
755 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
756 {
757 if (mDefaultUniformBlocksDirty[shaderType])
758 {
759 const angle::MemoryBuffer &uniformData = mDefaultUniformBlocks[shaderType].uniformData;
760 memcpy(&bufferData[offsets[shaderType]], uniformData.data(), uniformData.size());
761 mExecutable.mDynamicUniformDescriptorOffsets[offsetIndex] =
762 static_cast<uint32_t>(bufferOffset + offsets[shaderType]);
763 mDefaultUniformBlocksDirty.reset(shaderType);
764 }
765 ++offsetIndex;
766 }
767 ANGLE_TRY(defaultUniformStorage->flush(contextVk));
768
769 vk::BufferHelper *defaultUniformBuffer = defaultUniformStorage->getCurrentBuffer();
770 if (mExecutable.getCurrentDefaultUniformBufferSerial() !=
771 defaultUniformBuffer->getBufferSerial())
772 {
773 // We need to reinitialize the descriptor sets if we newly allocated buffers since we can't
774 // modify the descriptor sets once initialized.
775 vk::UniformsAndXfbDescriptorDesc defaultUniformsDesc;
776 vk::UniformsAndXfbDescriptorDesc *uniformsAndXfbBufferDesc;
777
778 if (glExecutable.hasTransformFeedbackOutput())
779 {
780 const gl::State &glState = contextVk->getState();
781 TransformFeedbackVk *transformFeedbackVk =
782 vk::GetImpl(glState.getCurrentTransformFeedback());
783 uniformsAndXfbBufferDesc = &transformFeedbackVk->getTransformFeedbackDesc();
784 uniformsAndXfbBufferDesc->updateDefaultUniformBuffer(
785 defaultUniformBuffer->getBufferSerial());
786 }
787 else
788 {
789 defaultUniformsDesc.updateDefaultUniformBuffer(defaultUniformBuffer->getBufferSerial());
790 uniformsAndXfbBufferDesc = &defaultUniformsDesc;
791 }
792
793 bool newDescriptorSetAllocated;
794 ANGLE_TRY(mExecutable.allocUniformAndXfbDescriptorSet(contextVk, *uniformsAndXfbBufferDesc,
795 &newDescriptorSetAllocated));
796 if (newDescriptorSetAllocated)
797 {
798 // Update the descriptor set with the bufferInfo
799 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
800 {
801 mExecutable.updateDefaultUniformsDescriptorSet(
802 shaderType, mDefaultUniformBlocks[shaderType], defaultUniformBuffer, contextVk);
803 }
804 mExecutable.updateTransformFeedbackDescriptorSetImpl(mState, contextVk);
805 }
806 }
807
808 return angle::Result::Continue;
809 }
810
setAllDefaultUniformsDirty()811 void ProgramVk::setAllDefaultUniformsDirty()
812 {
813 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
814 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
815 {
816 setShaderUniformDirtyBit(shaderType);
817 }
818 }
819
onProgramBind()820 void ProgramVk::onProgramBind()
821 {
822 // Because all programs share default uniform buffers, when we switch programs, we have to
823 // re-update all uniform data. We could do more tracking to avoid update if the context's
824 // current uniform buffer is still the same buffer we last time used and buffer has not been
825 // recycled. But statistics gathered on gfxbench shows that app always update uniform data on
826 // program bind anyway, so not really worth it to add more tracking logic here.
827 setAllDefaultUniformsDirty();
828 }
829 } // namespace rx
830