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/renderer_utils.h"
17 #include "libANGLE/renderer/vulkan/BufferVk.h"
18 #include "libANGLE/renderer/vulkan/TextureVk.h"
19
20 namespace rx
21 {
22
23 namespace
24 {
25 // Identical to Std140 encoder in all aspects, except it ignores opaque uniform types.
26 class VulkanDefaultBlockEncoder : public sh::Std140BlockEncoder
27 {
28 public:
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)29 void advanceOffset(GLenum type,
30 const std::vector<unsigned int> &arraySizes,
31 bool isRowMajorMatrix,
32 int arrayStride,
33 int matrixStride) override
34 {
35 if (gl::IsOpaqueType(type))
36 {
37 return;
38 }
39
40 sh::Std140BlockEncoder::advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride,
41 matrixStride);
42 }
43 };
44
InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> & uniforms,sh::BlockLayoutMap * blockLayoutMapOut,size_t * blockSizeOut)45 void InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> &uniforms,
46 sh::BlockLayoutMap *blockLayoutMapOut,
47 size_t *blockSizeOut)
48 {
49 if (uniforms.empty())
50 {
51 *blockSizeOut = 0;
52 return;
53 }
54
55 VulkanDefaultBlockEncoder blockEncoder;
56 sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut);
57
58 size_t blockSize = blockEncoder.getCurrentOffset();
59
60 // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized.
61 if (blockSize == 0)
62 {
63 *blockSizeOut = 0;
64 return;
65 }
66
67 *blockSizeOut = blockSize;
68 return;
69 }
70
71 template <typename T>
UpdateDefaultUniformBlock(GLsizei count,uint32_t arrayIndex,int componentCount,const T * v,const sh::BlockMemberInfo & layoutInfo,angle::MemoryBuffer * uniformData)72 void UpdateDefaultUniformBlock(GLsizei count,
73 uint32_t arrayIndex,
74 int componentCount,
75 const T *v,
76 const sh::BlockMemberInfo &layoutInfo,
77 angle::MemoryBuffer *uniformData)
78 {
79 const int elementSize = sizeof(T) * componentCount;
80
81 uint8_t *dst = uniformData->data() + layoutInfo.offset;
82 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
83 {
84 uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride;
85 uint8_t *writePtr = dst + arrayOffset;
86 ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size());
87 memcpy(writePtr, v, elementSize * count);
88 }
89 else
90 {
91 // Have to respect the arrayStride between each element of the array.
92 int maxIndex = arrayIndex + count;
93 for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex;
94 writeIndex++, readIndex++)
95 {
96 const int arrayOffset = writeIndex * layoutInfo.arrayStride;
97 uint8_t *writePtr = dst + arrayOffset;
98 const T *readPtr = v + (readIndex * componentCount);
99 ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size());
100 memcpy(writePtr, readPtr, elementSize);
101 }
102 }
103 }
104
105 template <typename T>
ReadFromDefaultUniformBlock(int componentCount,uint32_t arrayIndex,T * dst,const sh::BlockMemberInfo & layoutInfo,const angle::MemoryBuffer * uniformData)106 void ReadFromDefaultUniformBlock(int componentCount,
107 uint32_t arrayIndex,
108 T *dst,
109 const sh::BlockMemberInfo &layoutInfo,
110 const angle::MemoryBuffer *uniformData)
111 {
112 ASSERT(layoutInfo.offset != -1);
113
114 const int elementSize = sizeof(T) * componentCount;
115 const uint8_t *source = uniformData->data() + layoutInfo.offset;
116
117 if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
118 {
119 const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride;
120 memcpy(dst, readPtr, elementSize);
121 }
122 else
123 {
124 // Have to respect the arrayStride between each element of the array.
125 const int arrayOffset = arrayIndex * layoutInfo.arrayStride;
126 const uint8_t *readPtr = source + arrayOffset;
127 memcpy(dst, readPtr, elementSize);
128 }
129 }
130
131 class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
132 {
133 public:
makeEncoder()134 sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
135 };
136 } // anonymous namespace
137
138 // ProgramVk implementation.
ProgramVk(const gl::ProgramState & state)139 ProgramVk::ProgramVk(const gl::ProgramState &state) : ProgramImpl(state) {}
140
141 ProgramVk::~ProgramVk() = default;
142
destroy(const gl::Context * context)143 void ProgramVk::destroy(const gl::Context *context)
144 {
145 ContextVk *contextVk = vk::GetImpl(context);
146 reset(contextVk);
147 }
148
reset(ContextVk * contextVk)149 void ProgramVk::reset(ContextVk *contextVk)
150 {
151 mSpvProgramInterfaceInfo = {};
152
153 mExecutable.reset(contextVk);
154 }
155
load(const gl::Context * context,gl::BinaryInputStream * stream,gl::InfoLog & infoLog)156 std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
157 gl::BinaryInputStream *stream,
158 gl::InfoLog &infoLog)
159 {
160 ContextVk *contextVk = vk::GetImpl(context);
161
162 reset(contextVk);
163
164 return mExecutable.load(contextVk, mState.getExecutable(), mState.isSeparable(), stream);
165 }
166
save(const gl::Context * context,gl::BinaryOutputStream * stream)167 void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream)
168 {
169 ContextVk *contextVk = vk::GetImpl(context);
170 mExecutable.save(contextVk, mState.isSeparable(), stream);
171 }
172
setBinaryRetrievableHint(bool retrievable)173 void ProgramVk::setBinaryRetrievableHint(bool retrievable)
174 {
175 // Nothing to do here yet.
176 }
177
setSeparable(bool separable)178 void ProgramVk::setSeparable(bool separable)
179 {
180 // Nothing to do here yet.
181 }
182
link(const gl::Context * context,const gl::ProgramLinkedResources & resources,gl::InfoLog & infoLog,const gl::ProgramMergedVaryings & mergedVaryings)183 std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
184 const gl::ProgramLinkedResources &resources,
185 gl::InfoLog &infoLog,
186 const gl::ProgramMergedVaryings &mergedVaryings)
187 {
188 ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::link");
189
190 ContextVk *contextVk = vk::GetImpl(context);
191 // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
192 // assignment done in that function.
193 linkResources(context, resources);
194
195 reset(contextVk);
196 mExecutable.clearVariableInfoMap();
197
198 // Gather variable info and compiled SPIR-V binaries.
199 gl::ShaderMap<const angle::spirv::Blob *> spirvBlobs;
200 SpvSourceOptions options = SpvCreateSourceOptions(contextVk->getFeatures());
201 SpvGetShaderSpirvCode(context, options, mState, resources, &mSpvProgramInterfaceInfo,
202 &spirvBlobs, &mExecutable.mVariableInfoMap);
203
204 if (contextVk->getFeatures().varyingsRequireMatchingPrecisionInSpirv.enabled &&
205 contextVk->getFeatures().enablePrecisionQualifiers.enabled)
206 {
207 mExecutable.resolvePrecisionMismatch(mergedVaryings);
208 }
209
210 // Compile the shaders.
211 const gl::ProgramExecutable &programExecutable = mState.getExecutable();
212 angle::Result status = mExecutable.mOriginalShaderInfo.initShaders(
213 contextVk, programExecutable.getLinkedShaderStages(), spirvBlobs,
214 mExecutable.mVariableInfoMap);
215 if (status != angle::Result::Continue)
216 {
217 return std::make_unique<LinkEventDone>(status);
218 }
219
220 status = initDefaultUniformBlocks(context);
221 if (status != angle::Result::Continue)
222 {
223 return std::make_unique<LinkEventDone>(status);
224 }
225
226 // TODO(jie.a.chen@intel.com): Parallelize linking.
227 // http://crbug.com/849576
228 status = mExecutable.createPipelineLayout(contextVk, programExecutable, nullptr);
229 if (status != angle::Result::Continue)
230 {
231 return std::make_unique<LinkEventDone>(status);
232 }
233
234 // Warm up the pipeline cache by creating a few placeholder pipelines. This is not done for
235 // separable programs, and is deferred to when the program pipeline is finalized.
236 if (!mState.isSeparable())
237 {
238 status = mExecutable.warmUpPipelineCache(contextVk, programExecutable);
239 }
240 return std::make_unique<LinkEventDone>(status);
241 }
242
linkResources(const gl::Context * context,const gl::ProgramLinkedResources & resources)243 void ProgramVk::linkResources(const gl::Context *context,
244 const gl::ProgramLinkedResources &resources)
245 {
246 Std140BlockLayoutEncoderFactory std140EncoderFactory;
247 gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory);
248
249 linker.linkResources(context, mState, resources);
250 }
251
initDefaultUniformBlocks(const gl::Context * glContext)252 angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
253 {
254 ContextVk *contextVk = vk::GetImpl(glContext);
255
256 // Process vertex and fragment uniforms into std140 packing.
257 gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
258 gl::ShaderMap<size_t> requiredBufferSize;
259 requiredBufferSize.fill(0);
260
261 generateUniformLayoutMapping(glContext, layoutMap, requiredBufferSize);
262 initDefaultUniformLayoutMapping(layoutMap);
263
264 // All uniform initializations are complete, now resize the buffers accordingly and return
265 return mExecutable.resizeUniformBlockMemory(contextVk, mState.getExecutable(),
266 requiredBufferSize);
267 }
268
generateUniformLayoutMapping(const gl::Context * context,gl::ShaderMap<sh::BlockLayoutMap> & layoutMap,gl::ShaderMap<size_t> & requiredBufferSize)269 void ProgramVk::generateUniformLayoutMapping(const gl::Context *context,
270 gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
271 gl::ShaderMap<size_t> &requiredBufferSize)
272 {
273 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
274
275 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
276 {
277 gl::Shader *shader = mState.getAttachedShader(shaderType);
278
279 if (shader)
280 {
281 const std::vector<sh::ShaderVariable> &uniforms = shader->getUniforms(context);
282 InitDefaultUniformBlock(uniforms, &layoutMap[shaderType],
283 &requiredBufferSize[shaderType]);
284 }
285 }
286 }
287
initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> & layoutMap)288 void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap)
289 {
290 // Init the default block layout info.
291 const auto &uniforms = mState.getUniforms();
292 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
293
294 for (const gl::VariableLocation &location : mState.getUniformLocations())
295 {
296 gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
297
298 if (location.used() && !location.ignored)
299 {
300 const auto &uniform = uniforms[location.index];
301 if (uniform.isInDefaultBlock() && !uniform.isSampler() && !uniform.isImage() &&
302 !uniform.isFragmentInOut())
303 {
304 std::string uniformName = uniform.name;
305 if (uniform.isArray())
306 {
307 // Gets the uniform name without the [0] at the end.
308 uniformName = gl::StripLastArrayIndex(uniformName);
309 ASSERT(uniformName.size() != uniform.name.size());
310 }
311
312 bool found = false;
313
314 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
315 {
316 auto it = layoutMap[shaderType].find(uniformName);
317 if (it != layoutMap[shaderType].end())
318 {
319 found = true;
320 layoutInfo[shaderType] = it->second;
321 }
322 }
323
324 ASSERT(found);
325 }
326 }
327
328 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
329 {
330 mExecutable.mDefaultUniformBlocks[shaderType]->uniformLayout.push_back(
331 layoutInfo[shaderType]);
332 }
333 }
334 }
335
validate(const gl::Caps & caps,gl::InfoLog * infoLog)336 GLboolean ProgramVk::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
337 {
338 // No-op. The spec is very vague about the behavior of validation.
339 return GL_TRUE;
340 }
341
syncState(const gl::Context * context,const gl::Program::DirtyBits & dirtyBits)342 angle::Result ProgramVk::syncState(const gl::Context *context,
343 const gl::Program::DirtyBits &dirtyBits)
344 {
345 ASSERT(dirtyBits.any());
346 // Push dirty bits to executable so that they can be used later.
347 mExecutable.mDirtyBits |= dirtyBits;
348 return angle::Result::Continue;
349 }
350
351 template <typename T>
setUniformImpl(GLint location,GLsizei count,const T * v,GLenum entryPointType)352 void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType)
353 {
354 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
355 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
356 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
357
358 ASSERT(!linkedUniform.isSampler());
359
360 if (linkedUniform.typeInfo->type == entryPointType)
361 {
362 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
363 {
364 DefaultUniformBlock &uniformBlock = *mExecutable.mDefaultUniformBlocks[shaderType];
365 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
366
367 // Assume an offset of -1 means the block is unused.
368 if (layoutInfo.offset == -1)
369 {
370 continue;
371 }
372
373 const GLint componentCount = linkedUniform.typeInfo->componentCount;
374 UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo,
375 &uniformBlock.uniformData);
376 mExecutable.mDefaultUniformBlocksDirty.set(shaderType);
377 }
378 }
379 else
380 {
381 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
382 {
383 DefaultUniformBlock &uniformBlock = *mExecutable.mDefaultUniformBlocks[shaderType];
384 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
385
386 // Assume an offset of -1 means the block is unused.
387 if (layoutInfo.offset == -1)
388 {
389 continue;
390 }
391
392 const GLint componentCount = linkedUniform.typeInfo->componentCount;
393
394 ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType));
395
396 GLint initialArrayOffset =
397 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset;
398 for (GLint i = 0; i < count; i++)
399 {
400 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset;
401 GLint *dst =
402 reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset);
403 const T *source = v + i * componentCount;
404
405 for (int c = 0; c < componentCount; c++)
406 {
407 dst[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
408 }
409 }
410
411 mExecutable.mDefaultUniformBlocksDirty.set(shaderType);
412 }
413 }
414 }
415
416 template <typename T>
getUniformImpl(GLint location,T * v,GLenum entryPointType) const417 void ProgramVk::getUniformImpl(GLint location, T *v, GLenum entryPointType) const
418 {
419 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
420 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
421
422 ASSERT(!linkedUniform.isSampler() && !linkedUniform.isImage());
423
424 const gl::ShaderType shaderType = linkedUniform.getFirstActiveShaderType();
425 ASSERT(shaderType != gl::ShaderType::InvalidEnum);
426
427 const DefaultUniformBlock &uniformBlock = *mExecutable.mDefaultUniformBlocks[shaderType];
428 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
429
430 ASSERT(linkedUniform.typeInfo->componentType == entryPointType ||
431 linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType));
432
433 if (gl::IsMatrixType(linkedUniform.getType()))
434 {
435 const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset +
436 (locationInfo.arrayIndex * layoutInfo.arrayStride);
437 GetMatrixUniform(linkedUniform.getType(), v, reinterpret_cast<const T *>(ptrToElement),
438 false);
439 }
440 else
441 {
442 ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex,
443 v, layoutInfo, &uniformBlock.uniformData);
444 }
445 }
446
setUniform1fv(GLint location,GLsizei count,const GLfloat * v)447 void ProgramVk::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
448 {
449 setUniformImpl(location, count, v, GL_FLOAT);
450 }
451
setUniform2fv(GLint location,GLsizei count,const GLfloat * v)452 void ProgramVk::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
453 {
454 setUniformImpl(location, count, v, GL_FLOAT_VEC2);
455 }
456
setUniform3fv(GLint location,GLsizei count,const GLfloat * v)457 void ProgramVk::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
458 {
459 setUniformImpl(location, count, v, GL_FLOAT_VEC3);
460 }
461
setUniform4fv(GLint location,GLsizei count,const GLfloat * v)462 void ProgramVk::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
463 {
464 setUniformImpl(location, count, v, GL_FLOAT_VEC4);
465 }
466
setUniform1iv(GLint location,GLsizei count,const GLint * v)467 void ProgramVk::setUniform1iv(GLint location, GLsizei count, const GLint *v)
468 {
469 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
470 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
471 if (linkedUniform.isSampler())
472 {
473 // We could potentially cache some indexing here. For now this is a no-op since the mapping
474 // is handled entirely in ContextVk.
475 return;
476 }
477
478 setUniformImpl(location, count, v, GL_INT);
479 }
480
setUniform2iv(GLint location,GLsizei count,const GLint * v)481 void ProgramVk::setUniform2iv(GLint location, GLsizei count, const GLint *v)
482 {
483 setUniformImpl(location, count, v, GL_INT_VEC2);
484 }
485
setUniform3iv(GLint location,GLsizei count,const GLint * v)486 void ProgramVk::setUniform3iv(GLint location, GLsizei count, const GLint *v)
487 {
488 setUniformImpl(location, count, v, GL_INT_VEC3);
489 }
490
setUniform4iv(GLint location,GLsizei count,const GLint * v)491 void ProgramVk::setUniform4iv(GLint location, GLsizei count, const GLint *v)
492 {
493 setUniformImpl(location, count, v, GL_INT_VEC4);
494 }
495
setUniform1uiv(GLint location,GLsizei count,const GLuint * v)496 void ProgramVk::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
497 {
498 setUniformImpl(location, count, v, GL_UNSIGNED_INT);
499 }
500
setUniform2uiv(GLint location,GLsizei count,const GLuint * v)501 void ProgramVk::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
502 {
503 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2);
504 }
505
setUniform3uiv(GLint location,GLsizei count,const GLuint * v)506 void ProgramVk::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
507 {
508 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3);
509 }
510
setUniform4uiv(GLint location,GLsizei count,const GLuint * v)511 void ProgramVk::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
512 {
513 setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4);
514 }
515
516 template <int cols, int rows>
setUniformMatrixfv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)517 void ProgramVk::setUniformMatrixfv(GLint location,
518 GLsizei count,
519 GLboolean transpose,
520 const GLfloat *value)
521 {
522 const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
523 const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
524 const gl::ProgramExecutable &glExecutable = mState.getExecutable();
525
526 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
527 {
528 DefaultUniformBlock &uniformBlock = *mExecutable.mDefaultUniformBlocks[shaderType];
529 const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
530
531 // Assume an offset of -1 means the block is unused.
532 if (layoutInfo.offset == -1)
533 {
534 continue;
535 }
536
537 SetFloatUniformMatrixGLSL<cols, rows>::Run(
538 locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value,
539 uniformBlock.uniformData.data() + layoutInfo.offset);
540
541 mExecutable.mDefaultUniformBlocksDirty.set(shaderType);
542 }
543 }
544
setUniformMatrix2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)545 void ProgramVk::setUniformMatrix2fv(GLint location,
546 GLsizei count,
547 GLboolean transpose,
548 const GLfloat *value)
549 {
550 setUniformMatrixfv<2, 2>(location, count, transpose, value);
551 }
552
setUniformMatrix3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)553 void ProgramVk::setUniformMatrix3fv(GLint location,
554 GLsizei count,
555 GLboolean transpose,
556 const GLfloat *value)
557 {
558 setUniformMatrixfv<3, 3>(location, count, transpose, value);
559 }
560
setUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)561 void ProgramVk::setUniformMatrix4fv(GLint location,
562 GLsizei count,
563 GLboolean transpose,
564 const GLfloat *value)
565 {
566 setUniformMatrixfv<4, 4>(location, count, transpose, value);
567 }
568
setUniformMatrix2x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)569 void ProgramVk::setUniformMatrix2x3fv(GLint location,
570 GLsizei count,
571 GLboolean transpose,
572 const GLfloat *value)
573 {
574 setUniformMatrixfv<2, 3>(location, count, transpose, value);
575 }
576
setUniformMatrix3x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)577 void ProgramVk::setUniformMatrix3x2fv(GLint location,
578 GLsizei count,
579 GLboolean transpose,
580 const GLfloat *value)
581 {
582 setUniformMatrixfv<3, 2>(location, count, transpose, value);
583 }
584
setUniformMatrix2x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)585 void ProgramVk::setUniformMatrix2x4fv(GLint location,
586 GLsizei count,
587 GLboolean transpose,
588 const GLfloat *value)
589 {
590 setUniformMatrixfv<2, 4>(location, count, transpose, value);
591 }
592
setUniformMatrix4x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)593 void ProgramVk::setUniformMatrix4x2fv(GLint location,
594 GLsizei count,
595 GLboolean transpose,
596 const GLfloat *value)
597 {
598 setUniformMatrixfv<4, 2>(location, count, transpose, value);
599 }
600
setUniformMatrix3x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)601 void ProgramVk::setUniformMatrix3x4fv(GLint location,
602 GLsizei count,
603 GLboolean transpose,
604 const GLfloat *value)
605 {
606 setUniformMatrixfv<3, 4>(location, count, transpose, value);
607 }
608
setUniformMatrix4x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)609 void ProgramVk::setUniformMatrix4x3fv(GLint location,
610 GLsizei count,
611 GLboolean transpose,
612 const GLfloat *value)
613 {
614 setUniformMatrixfv<4, 3>(location, count, transpose, value);
615 }
616
getUniformfv(const gl::Context * context,GLint location,GLfloat * params) const617 void ProgramVk::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
618 {
619 getUniformImpl(location, params, GL_FLOAT);
620 }
621
getUniformiv(const gl::Context * context,GLint location,GLint * params) const622 void ProgramVk::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
623 {
624 getUniformImpl(location, params, GL_INT);
625 }
626
getUniformuiv(const gl::Context * context,GLint location,GLuint * params) const627 void ProgramVk::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
628 {
629 getUniformImpl(location, params, GL_UNSIGNED_INT);
630 }
631 } // namespace rx
632