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