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