jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 8 | #include "vk/GrVkPipelineStateBuilder.h" |
Brian Osman | 8a83ca4 | 2018-02-12 14:32:17 -0500 | [diff] [blame] | 9 | #include "GrContext.h" |
| 10 | #include "GrContextPriv.h" |
Brian Salomon | 94efbf5 | 2016-11-29 13:43:05 -0500 | [diff] [blame] | 11 | #include "GrShaderCaps.h" |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 12 | #include "GrStencilSettings.h" |
| 13 | #include "GrVkRenderTarget.h" |
egdaniel | 707bbd6 | 2016-07-26 07:19:47 -0700 | [diff] [blame] | 14 | #include "vk/GrVkDescriptorSetManager.h" |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 15 | #include "vk/GrVkGpu.h" |
| 16 | #include "vk/GrVkRenderPass.h" |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 17 | |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 18 | GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState( |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 19 | GrVkGpu* gpu, |
Brian Salomon | ff168d9 | 2018-06-23 15:17:27 -0400 | [diff] [blame] | 20 | const GrPrimitiveProcessor& primProc, |
Greg Daniel | 9a51a86 | 2018-11-30 10:18:14 -0500 | [diff] [blame] | 21 | const GrTextureProxy* const primProcProxies[], |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 22 | const GrPipeline& pipeline, |
| 23 | const GrStencilSettings& stencil, |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 24 | GrPrimitiveType primitiveType, |
| 25 | Desc* desc, |
Greg Daniel | 99b88e0 | 2018-10-03 15:31:20 -0400 | [diff] [blame] | 26 | VkRenderPass compatibleRenderPass) { |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 27 | // create a builder. This will be handed off to effects so they can use it to add |
| 28 | // uniforms, varyings, textures, etc |
Greg Daniel | 9a51a86 | 2018-11-30 10:18:14 -0500 | [diff] [blame] | 29 | GrVkPipelineStateBuilder builder(gpu, pipeline, primProc, primProcProxies, desc); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 30 | |
Ethan Nicholas | 2983f40 | 2017-05-08 09:36:08 -0400 | [diff] [blame] | 31 | if (!builder.emitAndInstallProcs()) { |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 32 | return nullptr; |
| 33 | } |
| 34 | |
Greg Daniel | 99b88e0 | 2018-10-03 15:31:20 -0400 | [diff] [blame] | 35 | return builder.finalize(stencil, primitiveType, compatibleRenderPass, desc); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 36 | } |
| 37 | |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 38 | GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu, |
| 39 | const GrPipeline& pipeline, |
| 40 | const GrPrimitiveProcessor& primProc, |
Greg Daniel | 9a51a86 | 2018-11-30 10:18:14 -0500 | [diff] [blame] | 41 | const GrTextureProxy* const primProcProxies[], |
Ethan Nicholas | 3865711 | 2017-02-09 17:01:22 -0500 | [diff] [blame] | 42 | GrProgramDesc* desc) |
Greg Daniel | 9a51a86 | 2018-11-30 10:18:14 -0500 | [diff] [blame] | 43 | : INHERITED(primProc, primProcProxies, pipeline, desc) |
Brian Salomon | ff168d9 | 2018-06-23 15:17:27 -0400 | [diff] [blame] | 44 | , fGpu(gpu) |
| 45 | , fVaryingHandler(this) |
| 46 | , fUniformHandler(this) {} |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 47 | |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 48 | const GrCaps* GrVkPipelineStateBuilder::caps() const { |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 49 | return fGpu->caps(); |
| 50 | } |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 51 | |
Brian Salomon | 99938a8 | 2016-11-21 13:41:08 -0500 | [diff] [blame] | 52 | void GrVkPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) { |
Brian Salomon | 6039768 | 2016-11-22 15:06:46 -0500 | [diff] [blame] | 53 | outputColor.addLayoutQualifier("location = 0, index = 0"); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 54 | } |
| 55 | |
Brian Salomon | 99938a8 | 2016-11-21 13:41:08 -0500 | [diff] [blame] | 56 | void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) { |
Brian Salomon | 6039768 | 2016-11-22 15:06:46 -0500 | [diff] [blame] | 57 | outputColor.addLayoutQualifier("location = 0, index = 1"); |
egdaniel | d632bb4 | 2016-03-30 12:06:48 -0700 | [diff] [blame] | 58 | } |
| 59 | |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 60 | bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage, |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 61 | const GrGLSLShaderBuilder& builder, |
| 62 | VkShaderModule* shaderModule, |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 63 | VkPipelineShaderStageCreateInfo* stageInfo, |
Ethan Nicholas | 3865711 | 2017-02-09 17:01:22 -0500 | [diff] [blame] | 64 | const SkSL::Program::Settings& settings, |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 65 | Desc* desc) { |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 66 | SkString shaderString; |
| 67 | for (int i = 0; i < builder.fCompilerStrings.count(); ++i) { |
| 68 | if (builder.fCompilerStrings[i]) { |
| 69 | shaderString.append(builder.fCompilerStrings[i]); |
| 70 | shaderString.append("\n"); |
| 71 | } |
| 72 | } |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 73 | |
| 74 | SkSL::Program::Inputs inputs; |
| 75 | bool result = GrCompileVkShaderModule(fGpu, shaderString.c_str(), stage, shaderModule, |
| 76 | stageInfo, settings, &inputs); |
| 77 | if (!result) { |
| 78 | return false; |
| 79 | } |
Greg Daniel | e6ab998 | 2018-08-22 13:56:32 +0000 | [diff] [blame] | 80 | if (inputs.fRTHeight) { |
| 81 | this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 82 | } |
Ethan Nicholas | 3865711 | 2017-02-09 17:01:22 -0500 | [diff] [blame] | 83 | if (inputs.fFlipY) { |
Robert Phillips | 7f86192 | 2018-01-30 13:13:42 +0000 | [diff] [blame] | 84 | desc->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( |
| 85 | this->pipeline().proxy()->origin())); |
Ethan Nicholas | 3865711 | 2017-02-09 17:01:22 -0500 | [diff] [blame] | 86 | desc->finalize(); |
| 87 | } |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 88 | return result; |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 89 | } |
| 90 | |
csmartdalton | c633abb | 2016-11-01 08:55:55 -0700 | [diff] [blame] | 91 | GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil, |
| 92 | GrPrimitiveType primitiveType, |
Greg Daniel | 99b88e0 | 2018-10-03 15:31:20 -0400 | [diff] [blame] | 93 | VkRenderPass compatibleRenderPass, |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 94 | Desc* desc) { |
Brian Salomon | 662ea4b | 2018-07-12 14:53:49 -0400 | [diff] [blame] | 95 | VkDescriptorSetLayout dsLayout[2]; |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 96 | VkPipelineLayout pipelineLayout; |
Greg Daniel | 852d715 | 2017-05-08 12:10:12 -0400 | [diff] [blame] | 97 | VkShaderModule vertShaderModule = VK_NULL_HANDLE; |
| 98 | VkShaderModule geomShaderModule = VK_NULL_HANDLE; |
| 99 | VkShaderModule fragShaderModule = VK_NULL_HANDLE; |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 100 | |
egdaniel | 707bbd6 | 2016-07-26 07:19:47 -0700 | [diff] [blame] | 101 | GrVkResourceProvider& resourceProvider = fGpu->resourceProvider(); |
Jim Van Verth | 684d7ce | 2016-11-17 13:30:22 -0500 | [diff] [blame] | 102 | // These layouts are not owned by the PipelineStateBuilder and thus should not be destroyed |
egdaniel | 707bbd6 | 2016-07-26 07:19:47 -0700 | [diff] [blame] | 103 | dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout(); |
| 104 | |
| 105 | GrVkDescriptorSetManager::Handle samplerDSHandle; |
Greg Daniel | a754378 | 2017-05-02 14:01:43 -0400 | [diff] [blame] | 106 | resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| 107 | fUniformHandler, &samplerDSHandle); |
egdaniel | 707bbd6 | 2016-07-26 07:19:47 -0700 | [diff] [blame] | 108 | dsLayout[GrVkUniformHandler::kSamplerDescSet] = |
| 109 | resourceProvider.getSamplerDSLayout(samplerDSHandle); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 110 | |
| 111 | // Create the VkPipelineLayout |
| 112 | VkPipelineLayoutCreateInfo layoutCreateInfo; |
| 113 | memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags)); |
| 114 | layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |
| 115 | layoutCreateInfo.pNext = 0; |
| 116 | layoutCreateInfo.flags = 0; |
Brian Salomon | 662ea4b | 2018-07-12 14:53:49 -0400 | [diff] [blame] | 117 | layoutCreateInfo.setLayoutCount = 2; |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 118 | layoutCreateInfo.pSetLayouts = dsLayout; |
| 119 | layoutCreateInfo.pushConstantRangeCount = 0; |
| 120 | layoutCreateInfo.pPushConstantRanges = nullptr; |
| 121 | |
| 122 | GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), CreatePipelineLayout(fGpu->device(), |
| 123 | &layoutCreateInfo, |
| 124 | nullptr, |
| 125 | &pipelineLayout)); |
| 126 | |
| 127 | // We need to enable the following extensions so that the compiler can correctly make spir-v |
| 128 | // from our glsl shaders. |
| 129 | fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n"); |
| 130 | fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n"); |
| 131 | fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n"); |
| 132 | fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n"); |
| 133 | |
| 134 | this->finalizeShaders(); |
| 135 | |
Greg Daniel | 852d715 | 2017-05-08 12:10:12 -0400 | [diff] [blame] | 136 | VkPipelineShaderStageCreateInfo shaderStageInfo[3]; |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 137 | SkSL::Program::Settings settings; |
Ethan Nicholas | e468286 | 2017-07-18 14:08:18 -0400 | [diff] [blame] | 138 | settings.fCaps = this->caps()->shaderCaps(); |
Robert Phillips | 2890fbf | 2017-07-26 15:48:41 -0400 | [diff] [blame] | 139 | settings.fFlipY = this->pipeline().proxy()->origin() != kTopLeft_GrSurfaceOrigin; |
Brian Osman | 8a83ca4 | 2018-02-12 14:32:17 -0500 | [diff] [blame] | 140 | settings.fSharpenTextures = this->gpu()->getContext()->contextPriv().sharpenMipmappedTextures(); |
Brian Salomon | dc09213 | 2018-04-04 10:14:16 -0400 | [diff] [blame] | 141 | SkASSERT(!this->fragColorIsInOut()); |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 142 | SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, |
| 143 | fVS, |
| 144 | &vertShaderModule, |
| 145 | &shaderStageInfo[0], |
Ethan Nicholas | 3865711 | 2017-02-09 17:01:22 -0500 | [diff] [blame] | 146 | settings, |
| 147 | desc)); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 148 | |
Ethan Nicholas | 941e7e2 | 2016-12-12 15:33:30 -0500 | [diff] [blame] | 149 | SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, |
| 150 | fFS, |
| 151 | &fragShaderModule, |
| 152 | &shaderStageInfo[1], |
Ethan Nicholas | 3865711 | 2017-02-09 17:01:22 -0500 | [diff] [blame] | 153 | settings, |
| 154 | desc)); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 155 | |
Greg Daniel | 852d715 | 2017-05-08 12:10:12 -0400 | [diff] [blame] | 156 | int numShaderStages = 2; // We always have at least vertex and fragment stages. |
| 157 | if (this->primitiveProcessor().willUseGeoShader()) { |
| 158 | SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT, |
| 159 | fGS, |
| 160 | &geomShaderModule, |
| 161 | &shaderStageInfo[2], |
| 162 | settings, |
| 163 | desc)); |
| 164 | ++numShaderStages; |
| 165 | } |
| 166 | |
Brian Salomon | ff168d9 | 2018-06-23 15:17:27 -0400 | [diff] [blame] | 167 | GrVkPipeline* pipeline = resourceProvider.createPipeline(fPrimProc, |
| 168 | fPipeline, |
csmartdalton | c633abb | 2016-11-01 08:55:55 -0700 | [diff] [blame] | 169 | stencil, |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 170 | shaderStageInfo, |
Greg Daniel | 852d715 | 2017-05-08 12:10:12 -0400 | [diff] [blame] | 171 | numShaderStages, |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 172 | primitiveType, |
Greg Daniel | 99b88e0 | 2018-10-03 15:31:20 -0400 | [diff] [blame] | 173 | compatibleRenderPass, |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 174 | pipelineLayout); |
| 175 | GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), vertShaderModule, |
| 176 | nullptr)); |
| 177 | GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), fragShaderModule, |
| 178 | nullptr)); |
Greg Daniel | 852d715 | 2017-05-08 12:10:12 -0400 | [diff] [blame] | 179 | // This if check should not be needed since calling destroy on a VK_NULL_HANDLE is allowed. |
| 180 | // However this is causing a crash in certain drivers (e.g. NVidia). |
| 181 | if (this->primitiveProcessor().willUseGeoShader()) { |
| 182 | GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), geomShaderModule, |
| 183 | nullptr)); |
| 184 | } |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 185 | |
| 186 | if (!pipeline) { |
| 187 | GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineLayout(fGpu->device(), pipelineLayout, |
| 188 | nullptr)); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 189 | return nullptr; |
| 190 | } |
| 191 | |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 192 | return new GrVkPipelineState(fGpu, |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 193 | pipeline, |
| 194 | pipelineLayout, |
egdaniel | 707bbd6 | 2016-07-26 07:19:47 -0700 | [diff] [blame] | 195 | samplerDSHandle, |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 196 | fUniformHandles, |
| 197 | fUniformHandler.fUniforms, |
Greg Daniel | 18f9602 | 2017-05-04 15:09:03 -0400 | [diff] [blame] | 198 | fUniformHandler.fCurrentGeometryUBOOffset, |
egdaniel | 22281c1 | 2016-03-23 13:49:40 -0700 | [diff] [blame] | 199 | fUniformHandler.fCurrentFragmentUBOOffset, |
Greg Daniel | 7a82edf | 2018-12-04 10:54:34 -0500 | [diff] [blame^] | 200 | fUniformHandler.fSamplers, |
Robert Phillips | 369e8b7 | 2017-08-01 16:13:04 -0400 | [diff] [blame] | 201 | std::move(fGeometryProcessor), |
| 202 | std::move(fXferProcessor), |
Brian Salomon | 4d3f517 | 2018-06-07 14:42:52 -0400 | [diff] [blame] | 203 | std::move(fFragmentProcessors), |
| 204 | fFragmentProcessorCnt); |
jvanverth | 992ad36 | 2016-02-26 09:21:02 -0800 | [diff] [blame] | 205 | } |
egdaniel | 707bbd6 | 2016-07-26 07:19:47 -0700 | [diff] [blame] | 206 | |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 207 | ////////////////////////////////////////////////////////////////////////////// |
| 208 | |
Chris Dalton | b91c466 | 2018-08-01 10:46:22 -0600 | [diff] [blame] | 209 | uint32_t get_blend_info_key(const GrPipeline& pipeline) { |
| 210 | GrXferProcessor::BlendInfo blendInfo; |
| 211 | pipeline.getXferProcessor().getBlendInfo(&blendInfo); |
| 212 | |
| 213 | static const uint32_t kBlendWriteShift = 1; |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 214 | static const uint32_t kBlendCoeffShift = 5; |
| 215 | GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << kBlendCoeffShift)); |
| 216 | GR_STATIC_ASSERT(kFirstAdvancedGrBlendEquation - 1 < 4); |
| 217 | |
Chris Dalton | b91c466 | 2018-08-01 10:46:22 -0600 | [diff] [blame] | 218 | uint32_t key = blendInfo.fWriteColor; |
| 219 | key |= (blendInfo.fSrcBlend << kBlendWriteShift); |
| 220 | key |= (blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift)); |
| 221 | key |= (blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift)); |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 222 | |
| 223 | return key; |
| 224 | } |
| 225 | |
| 226 | bool GrVkPipelineStateBuilder::Desc::Build(Desc* desc, |
| 227 | const GrPrimitiveProcessor& primProc, |
| 228 | const GrPipeline& pipeline, |
| 229 | const GrStencilSettings& stencil, |
| 230 | GrPrimitiveType primitiveType, |
Greg Daniel | 7a82edf | 2018-12-04 10:54:34 -0500 | [diff] [blame^] | 231 | GrVkGpu* gpu) { |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 232 | if (!INHERITED::Build(desc, primProc, primitiveType == GrPrimitiveType::kPoints, pipeline, |
Greg Daniel | 7a82edf | 2018-12-04 10:54:34 -0500 | [diff] [blame^] | 233 | gpu)) { |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 234 | return false; |
| 235 | } |
| 236 | |
| 237 | GrProcessorKeyBuilder b(&desc->key()); |
| 238 | GrVkRenderTarget* vkRT = (GrVkRenderTarget*)pipeline.renderTarget(); |
| 239 | vkRT->simpleRenderPass()->genKey(&b); |
| 240 | |
| 241 | stencil.genKey(&b); |
| 242 | |
Chris Dalton | b91c466 | 2018-08-01 10:46:22 -0600 | [diff] [blame] | 243 | b.add32(get_blend_info_key(pipeline)); |
Brian Salomon | 1471df9 | 2018-06-08 10:49:00 -0400 | [diff] [blame] | 244 | |
| 245 | b.add32((uint32_t)primitiveType); |
| 246 | |
| 247 | return true; |
| 248 | } |