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 8#include "src/gpu/vk/GrVkPipelineState.h" 9 10#include "src/core/SkMipmap.h" 11#include "src/gpu/GrFragmentProcessor.h" 12#include "src/gpu/GrGeometryProcessor.h" 13#include "src/gpu/GrPipeline.h" 14#include "src/gpu/GrRenderTarget.h" 15#include "src/gpu/GrTexture.h" 16#include "src/gpu/GrXferProcessor.h" 17#include "src/gpu/effects/GrTextureEffect.h" 18#include "src/gpu/vk/GrVkBuffer.h" 19#include "src/gpu/vk/GrVkCommandBuffer.h" 20#include "src/gpu/vk/GrVkDescriptorPool.h" 21#include "src/gpu/vk/GrVkDescriptorSet.h" 22#include "src/gpu/vk/GrVkGpu.h" 23#include "src/gpu/vk/GrVkImageView.h" 24#include "src/gpu/vk/GrVkMemory.h" 25#include "src/gpu/vk/GrVkPipeline.h" 26#include "src/gpu/vk/GrVkRenderTarget.h" 27#include "src/gpu/vk/GrVkSampler.h" 28#include "src/gpu/vk/GrVkTexture.h" 29 30GrVkPipelineState::GrVkPipelineState( 31 GrVkGpu* gpu, 32 sk_sp<const GrVkPipeline> pipeline, 33 const GrVkDescriptorSetManager::Handle& samplerDSHandle, 34 const GrGLSLBuiltinUniformHandles& builtinUniformHandles, 35 const UniformInfoArray& uniforms, 36 uint32_t uniformSize, 37 bool usePushConstants, 38 const UniformInfoArray& samplers, 39 std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl, 40 std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl, 41 std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls) 42 : fPipeline(std::move(pipeline)) 43 , fSamplerDSHandle(samplerDSHandle) 44 , fBuiltinUniformHandles(builtinUniformHandles) 45 , fGPImpl(std::move(gpImpl)) 46 , fXPImpl(std::move(xpImpl)) 47 , fFPImpls(std::move(fpImpls)) 48 , fDataManager(uniforms, uniformSize, usePushConstants) { 49 fNumSamplers = samplers.count(); 50 for (const auto& sampler : samplers.items()) { 51 // We store the immutable samplers here and take a ref on the sampler. Once we switch to 52 // using sk_sps here we should just move the immutable samplers to save the extra ref/unref. 53 if (sampler.fImmutableSampler) { 54 sampler.fImmutableSampler->ref(); 55 } 56 fImmutableSamplers.push_back(sampler.fImmutableSampler); 57 } 58} 59 60GrVkPipelineState::~GrVkPipelineState() { 61 // Must have freed all GPU resources before this is destroyed 62 SkASSERT(!fPipeline); 63} 64 65void GrVkPipelineState::freeGPUResources(GrVkGpu* gpu) { 66 fPipeline.reset(); 67 fDataManager.releaseData(); 68 for (int i = 0; i < fImmutableSamplers.count(); ++i) { 69 if (fImmutableSamplers[i]) { 70 fImmutableSamplers[i]->unref(); 71 fImmutableSamplers[i] = nullptr; 72 } 73 } 74} 75 76bool GrVkPipelineState::setAndBindUniforms(GrVkGpu* gpu, 77 SkISize colorAttachmentDimensions, 78 const GrProgramInfo& programInfo, 79 GrVkCommandBuffer* commandBuffer) { 80 this->setRenderTargetState(colorAttachmentDimensions, programInfo.origin()); 81 82 fGPImpl->setData(fDataManager, *gpu->caps()->shaderCaps(), programInfo.geomProc()); 83 84 for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) { 85 const auto& fp = programInfo.pipeline().getFragmentProcessor(i); 86 fp.visitWithImpls([&](const GrFragmentProcessor& fp, 87 GrFragmentProcessor::ProgramImpl& impl) { 88 impl.setData(fDataManager, fp); 89 }, *fFPImpls[i]); 90 } 91 92 programInfo.pipeline().setDstTextureUniforms(fDataManager, &fBuiltinUniformHandles); 93 fXPImpl->setData(fDataManager, programInfo.pipeline().getXferProcessor()); 94 95 // Upload uniform data and bind descriptor set. 96 auto [uniformBuffer, success] = fDataManager.uploadUniforms(gpu, fPipeline->layout(), 97 commandBuffer); 98 if (!success) { 99 return false; 100 } 101 if (uniformBuffer) { 102 const GrVkBuffer* vkBuffer = static_cast<GrVkBuffer*>(uniformBuffer.get()); 103 static const int kUniformDSIdx = GrVkUniformHandler::kUniformBufferDescSet; 104 commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), kUniformDSIdx, /*setCount=*/1, 105 vkBuffer->uniformDescriptorSet(), 106 /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr); 107 commandBuffer->addGrBuffer(std::move(uniformBuffer)); 108 } 109 return true; 110} 111 112bool GrVkPipelineState::setAndBindTextures(GrVkGpu* gpu, 113 const GrGeometryProcessor& geomProc, 114 const GrPipeline& pipeline, 115 const GrSurfaceProxy* const geomProcTextures[], 116 GrVkCommandBuffer* commandBuffer) { 117 SkASSERT(geomProcTextures || !geomProc.numTextureSamplers()); 118 if (!fNumSamplers) { 119 return true; 120 } 121 struct SamplerBindings { 122 GrSamplerState fState; 123 GrVkTexture* fTexture; 124 }; 125 SkAutoSTArray<8, SamplerBindings> samplerBindings(fNumSamplers); 126 int currTextureBinding = 0; 127 128 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) { 129 SkASSERT(geomProcTextures[i]->asTextureProxy()); 130 const auto& sampler = geomProc.textureSampler(i); 131 auto texture = static_cast<GrVkTexture*>(geomProcTextures[i]->peekTexture()); 132 samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture}; 133 } 134 135 136 if (GrTexture* dstTexture = pipeline.peekDstTexture()) { 137 samplerBindings[currTextureBinding++] = {GrSamplerState::Filter::kNearest, 138 static_cast<GrVkTexture*>(dstTexture)}; 139 } 140 141 pipeline.visitTextureEffects([&](const GrTextureEffect& te) { 142 GrSamplerState samplerState = te.samplerState(); 143 auto* texture = static_cast<GrVkTexture*>(te.texture()); 144 samplerBindings[currTextureBinding++] = {samplerState, texture}; 145 }); 146 147 // Get new descriptor set 148 SkASSERT(fNumSamplers == currTextureBinding); 149 static const int kSamplerDSIdx = GrVkUniformHandler::kSamplerDescSet; 150 151 if (fNumSamplers == 1) { 152 auto texture = samplerBindings[0].fTexture; 153 auto texAttachment = texture->textureImage(); 154 const auto& samplerState = samplerBindings[0].fState; 155 const GrVkDescriptorSet* descriptorSet = texture->cachedSingleDescSet(samplerState); 156 if (descriptorSet) { 157 commandBuffer->addGrSurface(sk_ref_sp<const GrSurface>(texture)); 158 commandBuffer->addResource(texAttachment->textureView()); 159 commandBuffer->addResource(texAttachment->resource()); 160 commandBuffer->addRecycledResource(descriptorSet); 161 commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), kSamplerDSIdx, 162 /*setCount=*/1, descriptorSet->descriptorSet(), 163 /*dynamicOffsetCount=*/0, 164 /*dynamicOffsets=*/nullptr); 165 return true; 166 } 167 } 168 169 const GrVkDescriptorSet* descriptorSet = 170 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle); 171 if (!descriptorSet) { 172 return false; 173 } 174 175 for (int i = 0; i < fNumSamplers; ++i) { 176 GrSamplerState state = samplerBindings[i].fState; 177 GrVkTexture* texture = samplerBindings[i].fTexture; 178 auto texAttachment = texture->textureImage(); 179 180 const GrVkImageView* textureView = texAttachment->textureView(); 181 const GrVkSampler* sampler = nullptr; 182 if (fImmutableSamplers[i]) { 183 sampler = fImmutableSamplers[i]; 184 } else { 185 sampler = gpu->resourceProvider().findOrCreateCompatibleSampler( 186 state, texAttachment->ycbcrConversionInfo()); 187 if (!sampler) { 188 descriptorSet->recycle(); 189 return false; 190 } 191 } 192 SkASSERT(sampler); 193 194 VkDescriptorImageInfo imageInfo; 195 memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo)); 196 imageInfo.sampler = fImmutableSamplers[i] ? VK_NULL_HANDLE : sampler->sampler(); 197 imageInfo.imageView = textureView->imageView(); 198 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 199 200 VkWriteDescriptorSet writeInfo; 201 memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet)); 202 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 203 writeInfo.pNext = nullptr; 204 writeInfo.dstSet = *descriptorSet->descriptorSet(); 205 writeInfo.dstBinding = i; 206 writeInfo.dstArrayElement = 0; 207 writeInfo.descriptorCount = 1; 208 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 209 writeInfo.pImageInfo = &imageInfo; 210 writeInfo.pBufferInfo = nullptr; 211 writeInfo.pTexelBufferView = nullptr; 212 213 GR_VK_CALL(gpu->vkInterface(), 214 UpdateDescriptorSets(gpu->device(), 1, &writeInfo, 0, nullptr)); 215 commandBuffer->addResource(sampler); 216 if (!fImmutableSamplers[i]) { 217 sampler->unref(); 218 } 219 commandBuffer->addResource(textureView); 220 commandBuffer->addResource(texAttachment->resource()); 221 } 222 if (fNumSamplers == 1) { 223 GrSamplerState state = samplerBindings[0].fState; 224 GrVkTexture* texture = samplerBindings[0].fTexture; 225 texture->addDescriptorSetToCache(descriptorSet, state); 226 } 227 228 commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), kSamplerDSIdx, /*setCount=*/1, 229 descriptorSet->descriptorSet(), 230 /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr); 231 commandBuffer->addRecycledResource(descriptorSet); 232 descriptorSet->recycle(); 233 return true; 234} 235 236bool GrVkPipelineState::setAndBindInputAttachment(GrVkGpu* gpu, 237 gr_rp<const GrVkDescriptorSet> inputDescSet, 238 GrVkCommandBuffer* commandBuffer) { 239 SkASSERT(inputDescSet); 240 commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), GrVkUniformHandler::kInputDescSet, 241 /*setCount=*/1, inputDescSet->descriptorSet(), 242 /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr); 243 // We don't add the input resource to the command buffer to track since the input will be 244 // the same as the color attachment which is already tracked on the command buffer. 245 commandBuffer->addRecycledResource(std::move(inputDescSet)); 246 return true; 247} 248 249void GrVkPipelineState::setRenderTargetState(SkISize colorAttachmentDimensions, 250 GrSurfaceOrigin origin) { 251 // Set RT adjustment and RT flip 252 SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); 253 if (fRenderTargetState.fRenderTargetOrigin != origin || 254 fRenderTargetState.fRenderTargetSize != colorAttachmentDimensions) { 255 fRenderTargetState.fRenderTargetSize = colorAttachmentDimensions; 256 fRenderTargetState.fRenderTargetOrigin = origin; 257 258 // The client will mark a swap buffer as kTopLeft when making a SkSurface because 259 // Vulkan's framebuffer space has (0, 0) at the top left. This agrees with Skia's device 260 // coords and with Vulkan's NDC that has (-1, -1) in the top left. So a flip is needed when 261 // surface origin is kBottomLeft rather than kTopLeft. 262 bool flip = (origin == kBottomLeft_GrSurfaceOrigin); 263 std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(colorAttachmentDimensions, flip); 264 fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data()); 265 if (fBuiltinUniformHandles.fRTFlipUni.isValid()) { 266 std::array<float, 2> d = 267 SkSL::Compiler::GetRTFlipVector(colorAttachmentDimensions.height(), flip); 268 fDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data()); 269 } 270 } 271} 272 273void GrVkPipelineState::bindPipeline(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) { 274 commandBuffer->bindPipeline(gpu, fPipeline); 275} 276