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/GrPipeline.h"
12 #include "src/gpu/GrRenderTarget.h"
13 #include "src/gpu/GrTexture.h"
14 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
15 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
16 #include "src/gpu/glsl/GrGLSLXferProcessor.h"
17 #include "src/gpu/vk/GrVkCommandBuffer.h"
18 #include "src/gpu/vk/GrVkDescriptorPool.h"
19 #include "src/gpu/vk/GrVkDescriptorSet.h"
20 #include "src/gpu/vk/GrVkGpu.h"
21 #include "src/gpu/vk/GrVkImageView.h"
22 #include "src/gpu/vk/GrVkMemory.h"
23 #include "src/gpu/vk/GrVkPipeline.h"
24 #include "src/gpu/vk/GrVkRenderTarget.h"
25 #include "src/gpu/vk/GrVkSampler.h"
26 #include "src/gpu/vk/GrVkTexture.h"
27 #include "src/gpu/vk/GrVkUniformBuffer.h"
28 
GrVkPipelineState(GrVkGpu * gpu,GrVkPipeline * pipeline,const GrVkDescriptorSetManager::Handle & samplerDSHandle,const GrGLSLBuiltinUniformHandles & builtinUniformHandles,const UniformInfoArray & uniforms,uint32_t uniformSize,const UniformInfoArray & samplers,std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,std::unique_ptr<GrGLSLXferProcessor> xferProcessor,std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors)29 GrVkPipelineState::GrVkPipelineState(
30         GrVkGpu* gpu,
31         GrVkPipeline* pipeline,
32         const GrVkDescriptorSetManager::Handle& samplerDSHandle,
33         const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
34         const UniformInfoArray& uniforms,
35         uint32_t uniformSize,
36         const UniformInfoArray& samplers,
37         std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
38         std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
39         std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors)
40         : fPipeline(pipeline)
41         , fSamplerDSHandle(samplerDSHandle)
42         , fBuiltinUniformHandles(builtinUniformHandles)
43         , fGeometryProcessor(std::move(geometryProcessor))
44         , fXferProcessor(std::move(xferProcessor))
45         , fFragmentProcessors(std::move(fragmentProcessors))
46         , fDataManager(uniforms, uniformSize) {
47     fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, uniformSize));
48 
49     fNumSamplers = samplers.count();
50     for (const auto& sampler : samplers.items()) {
51         // We store the immutable samplers here and take ownership of the ref from the
52         // GrVkUnformHandler.
53         fImmutableSamplers.push_back(sampler.fImmutableSampler);
54     }
55 }
56 
~GrVkPipelineState()57 GrVkPipelineState::~GrVkPipelineState() {
58     // Must have freed all GPU resources before this is destroyed
59     SkASSERT(!fPipeline);
60 }
61 
freeGPUResources(GrVkGpu * gpu)62 void GrVkPipelineState::freeGPUResources(GrVkGpu* gpu) {
63     if (fPipeline) {
64         fPipeline->unref();
65         fPipeline = nullptr;
66     }
67 
68     if (fUniformBuffer) {
69         fUniformBuffer->release(gpu);
70         fUniformBuffer.reset();
71     }
72 }
73 
setAndBindUniforms(GrVkGpu * gpu,const GrRenderTarget * renderTarget,const GrProgramInfo & programInfo,GrVkCommandBuffer * commandBuffer)74 bool GrVkPipelineState::setAndBindUniforms(GrVkGpu* gpu,
75                                            const GrRenderTarget* renderTarget,
76                                            const GrProgramInfo& programInfo,
77                                            GrVkCommandBuffer* commandBuffer) {
78     this->setRenderTargetState(renderTarget, programInfo.origin());
79 
80     fGeometryProcessor->setData(fDataManager, programInfo.primProc());
81     for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
82         auto& pipelineFP = programInfo.pipeline().getFragmentProcessor(i);
83         auto& baseGLSLFP = *fFragmentProcessors[i];
84         for (auto [fp, glslFP] : GrGLSLFragmentProcessor::ParallelRange(pipelineFP, baseGLSLFP)) {
85             glslFP.setData(fDataManager, fp);
86         }
87     }
88 
89     {
90         SkIPoint offset;
91         GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset);
92 
93         fXferProcessor->setData(fDataManager, programInfo.pipeline().getXferProcessor(),
94                                 dstTexture, offset);
95     }
96 
97     // Get new descriptor set
98     if (fUniformBuffer) {
99         fDataManager.uploadUniformBuffers(gpu, fUniformBuffer.get());
100         static const int kUniformDSIdx = GrVkUniformHandler::kUniformBufferDescSet;
101         commandBuffer->bindDescriptorSets(gpu, this, fPipeline->layout(), kUniformDSIdx, 1,
102                                           fUniformBuffer->descriptorSet(), 0, nullptr);
103         commandBuffer->addRecycledResource(fUniformBuffer->resource());
104     }
105     return true;
106 }
107 
setAndBindTextures(GrVkGpu * gpu,const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline,const GrSurfaceProxy * const primProcTextures[],GrVkCommandBuffer * commandBuffer)108 bool GrVkPipelineState::setAndBindTextures(GrVkGpu* gpu,
109                                            const GrPrimitiveProcessor& primProc,
110                                            const GrPipeline& pipeline,
111                                            const GrSurfaceProxy* const primProcTextures[],
112                                            GrVkCommandBuffer* commandBuffer) {
113     SkASSERT(primProcTextures || !primProc.numTextureSamplers());
114     if (fNumSamplers) {
115         struct SamplerBindings {
116             GrSamplerState fState;
117             GrVkTexture* fTexture;
118         };
119         SkAutoSTMalloc<8, SamplerBindings> samplerBindings(fNumSamplers);
120         int currTextureBinding = 0;
121 
122         for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
123             SkASSERT(primProcTextures[i]->asTextureProxy());
124             const auto& sampler = primProc.textureSampler(i);
125             auto texture = static_cast<GrVkTexture*>(primProcTextures[i]->peekTexture());
126             samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture};
127         }
128 
129         pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
130             GrSamplerState samplerState = te.samplerState();
131             auto* texture = static_cast<GrVkTexture*>(te.texture());
132             samplerBindings[currTextureBinding++] = {samplerState, texture};
133         });
134 
135         if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
136             samplerBindings[currTextureBinding++] = {GrSamplerState::Filter::kNearest,
137                                                      static_cast<GrVkTexture*>(dstTexture)};
138         }
139 
140         // Get new descriptor set
141         SkASSERT(fNumSamplers == currTextureBinding);
142         static const int kSamplerDSIdx = GrVkUniformHandler::kSamplerDescSet;
143 
144         if (fNumSamplers == 1) {
145             auto texture = samplerBindings[0].fTexture;
146             const auto& samplerState = samplerBindings[0].fState;
147             const GrVkDescriptorSet* descriptorSet = texture->cachedSingleDescSet(samplerState);
148             if (descriptorSet) {
149                 commandBuffer->addGrSurface(sk_ref_sp<const GrSurface>(texture));
150                 commandBuffer->addResource(texture->textureView());
151                 commandBuffer->addResource(texture->resource());
152                 commandBuffer->addRecycledResource(descriptorSet);
153                 commandBuffer->bindDescriptorSets(gpu, this, fPipeline->layout(), kSamplerDSIdx, 1,
154                                                   descriptorSet->descriptorSet(), 0, nullptr);
155                 return true;
156             }
157         }
158 
159         const GrVkDescriptorSet* descriptorSet =
160                 gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
161         if (!descriptorSet) {
162             return false;
163         }
164 
165         for (int i = 0; i < fNumSamplers; ++i) {
166             GrSamplerState state = samplerBindings[i].fState;
167             GrVkTexture* texture = samplerBindings[i].fTexture;
168 
169             const GrVkImageView* textureView = texture->textureView();
170             const GrVkSampler* sampler = nullptr;
171             if (fImmutableSamplers[i]) {
172                 sampler = fImmutableSamplers[i];
173             } else {
174                 sampler = gpu->resourceProvider().findOrCreateCompatibleSampler(
175                         state, texture->ycbcrConversionInfo());
176             }
177             SkASSERT(sampler);
178 
179             VkDescriptorImageInfo imageInfo;
180             memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
181             imageInfo.sampler = fImmutableSamplers[i] ? VK_NULL_HANDLE : sampler->sampler();
182             imageInfo.imageView = textureView->imageView();
183             imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
184 
185             VkWriteDescriptorSet writeInfo;
186             memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
187             writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
188             writeInfo.pNext = nullptr;
189             writeInfo.dstSet = *descriptorSet->descriptorSet();
190             writeInfo.dstBinding = i;
191             writeInfo.dstArrayElement = 0;
192             writeInfo.descriptorCount = 1;
193             writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
194             writeInfo.pImageInfo = &imageInfo;
195             writeInfo.pBufferInfo = nullptr;
196             writeInfo.pTexelBufferView = nullptr;
197 
198             GR_VK_CALL(gpu->vkInterface(),
199                        UpdateDescriptorSets(gpu->device(), 1, &writeInfo, 0, nullptr));
200             commandBuffer->addResource(sampler);
201             if (!fImmutableSamplers[i]) {
202                 sampler->unref();
203             }
204             commandBuffer->addResource(samplerBindings[i].fTexture->textureView());
205             commandBuffer->addResource(samplerBindings[i].fTexture->resource());
206         }
207         if (fNumSamplers == 1) {
208             GrSamplerState state = samplerBindings[0].fState;
209             GrVkTexture* texture = samplerBindings[0].fTexture;
210             texture->addDescriptorSetToCache(descriptorSet, state);
211         }
212 
213         commandBuffer->bindDescriptorSets(gpu, this, fPipeline->layout(), kSamplerDSIdx, 1,
214                                           descriptorSet->descriptorSet(), 0, nullptr);
215         commandBuffer->addRecycledResource(descriptorSet);
216         descriptorSet->recycle();
217     }
218     return true;
219 }
220 
setAndBindInputAttachment(GrVkGpu * gpu,GrVkRenderTarget * renderTarget,GrVkCommandBuffer * commandBuffer)221 bool GrVkPipelineState::setAndBindInputAttachment(GrVkGpu* gpu,
222                                                   GrVkRenderTarget* renderTarget,
223                                                   GrVkCommandBuffer* commandBuffer) {
224     SkASSERT(renderTarget->supportsInputAttachmentUsage());
225     const GrVkDescriptorSet* descriptorSet = renderTarget->inputDescSet(gpu);
226     if (!descriptorSet) {
227         return false;
228     }
229     commandBuffer->bindDescriptorSets(gpu, this, fPipeline->layout(),
230                                       GrVkUniformHandler::kInputDescSet, /*setCount=*/1,
231                                       descriptorSet->descriptorSet(),
232                                       /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr);
233     // We don't add the input resource to the command buffer to track since the input will be
234     // the same as the color attachment which is already tracked on the command buffer.
235     commandBuffer->addRecycledResource(descriptorSet);
236     return true;
237 }
238 
setRenderTargetState(const GrRenderTarget * rt,GrSurfaceOrigin origin)239 void GrVkPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
240 
241     // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
242     if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
243         fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
244         fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
245     }
246 
247     // set RT adjustment
248     SkISize dimensions = rt->dimensions();
249     SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
250     if (fRenderTargetState.fRenderTargetOrigin != origin ||
251         fRenderTargetState.fRenderTargetSize != dimensions) {
252         fRenderTargetState.fRenderTargetSize = dimensions;
253         fRenderTargetState.fRenderTargetOrigin = origin;
254 
255         float rtAdjustmentVec[4];
256         fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
257         fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
258     }
259 }
260 
bindPipeline(const GrVkGpu * gpu,GrVkCommandBuffer * commandBuffer)261 void GrVkPipelineState::bindPipeline(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) {
262     commandBuffer->bindPipeline(gpu, fPipeline);
263 }
264