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