1 // Copyright 2020 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Context.hpp"
16
17 #include "Vulkan/VkBuffer.hpp"
18 #include "Vulkan/VkDevice.hpp"
19 #include "Vulkan/VkImageView.hpp"
20 #include "Vulkan/VkRenderPass.hpp"
21 #include "Vulkan/VkStringify.hpp"
22
23 namespace {
24
ComputePrimitiveCount(VkPrimitiveTopology topology,uint32_t vertexCount)25 uint32_t ComputePrimitiveCount(VkPrimitiveTopology topology, uint32_t vertexCount)
26 {
27 switch(topology)
28 {
29 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
30 return vertexCount;
31 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
32 return vertexCount / 2;
33 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
34 return std::max<uint32_t>(vertexCount, 1) - 1;
35 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
36 return vertexCount / 3;
37 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
38 return std::max<uint32_t>(vertexCount, 2) - 2;
39 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
40 return std::max<uint32_t>(vertexCount, 2) - 2;
41 default:
42 UNSUPPORTED("VkPrimitiveTopology %d", int(topology));
43 }
44
45 return 0;
46 }
47
48 template<typename T>
ProcessPrimitiveRestart(T * indexBuffer,VkPrimitiveTopology topology,uint32_t count,std::vector<std::pair<uint32_t,void * >> * indexBuffers)49 void ProcessPrimitiveRestart(T *indexBuffer,
50 VkPrimitiveTopology topology,
51 uint32_t count,
52 std::vector<std::pair<uint32_t, void *>> *indexBuffers)
53 {
54 static const T RestartIndex = static_cast<T>(-1);
55 T *indexBufferStart = indexBuffer;
56 uint32_t vertexCount = 0;
57 for(uint32_t i = 0; i < count; i++)
58 {
59 if(indexBuffer[i] == RestartIndex)
60 {
61 // Record previous segment
62 if(vertexCount > 0)
63 {
64 uint32_t primitiveCount = ComputePrimitiveCount(topology, vertexCount);
65 if(primitiveCount > 0)
66 {
67 indexBuffers->push_back({ primitiveCount, indexBufferStart });
68 }
69 }
70 vertexCount = 0;
71 }
72 else
73 {
74 if(vertexCount == 0)
75 {
76 indexBufferStart = indexBuffer + i;
77 }
78 vertexCount++;
79 }
80 }
81
82 // Record last segment
83 if(vertexCount > 0)
84 {
85 uint32_t primitiveCount = ComputePrimitiveCount(topology, vertexCount);
86 if(primitiveCount > 0)
87 {
88 indexBuffers->push_back({ primitiveCount, indexBufferStart });
89 }
90 }
91 }
92
93 } // namespace
94
95 namespace vk {
96
bytesPerIndex() const97 int IndexBuffer::bytesPerIndex() const
98 {
99 return indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
100 }
101
setIndexBufferBinding(const VertexInputBinding & indexBufferBinding,VkIndexType type)102 void IndexBuffer::setIndexBufferBinding(const VertexInputBinding &indexBufferBinding, VkIndexType type)
103 {
104 binding = indexBufferBinding;
105 indexType = type;
106 }
107
getIndexBuffers(VkPrimitiveTopology topology,uint32_t count,uint32_t first,bool indexed,bool hasPrimitiveRestartEnable,std::vector<std::pair<uint32_t,void * >> * indexBuffers) const108 void IndexBuffer::getIndexBuffers(VkPrimitiveTopology topology, uint32_t count, uint32_t first, bool indexed, bool hasPrimitiveRestartEnable, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const
109 {
110 if(indexed)
111 {
112 void *indexBuffer = binding.buffer->getOffsetPointer(binding.offset + first * bytesPerIndex());
113 if(hasPrimitiveRestartEnable)
114 {
115 switch(indexType)
116 {
117 case VK_INDEX_TYPE_UINT16:
118 ProcessPrimitiveRestart(static_cast<uint16_t *>(indexBuffer), topology, count, indexBuffers);
119 break;
120 case VK_INDEX_TYPE_UINT32:
121 ProcessPrimitiveRestart(static_cast<uint32_t *>(indexBuffer), topology, count, indexBuffers);
122 break;
123 default:
124 UNSUPPORTED("VkIndexType %d", int(indexType));
125 }
126 }
127 else
128 {
129 indexBuffers->push_back({ ComputePrimitiveCount(topology, count), indexBuffer });
130 }
131 }
132 else
133 {
134 indexBuffers->push_back({ ComputePrimitiveCount(topology, count), nullptr });
135 }
136 }
137
colorFormat(int index) const138 VkFormat Attachments::colorFormat(int index) const
139 {
140 ASSERT((index >= 0) && (index < sw::MAX_COLOR_BUFFERS));
141
142 if(colorBuffer[index])
143 {
144 return colorBuffer[index]->getFormat();
145 }
146 else
147 {
148 return VK_FORMAT_UNDEFINED;
149 }
150 }
151
depthFormat() const152 VkFormat Attachments::depthFormat() const
153 {
154 if(depthBuffer)
155 {
156 return depthBuffer->getFormat();
157 }
158 else
159 {
160 return VK_FORMAT_UNDEFINED;
161 }
162 }
163
Inputs(const VkPipelineVertexInputStateCreateInfo * vertexInputState)164 Inputs::Inputs(const VkPipelineVertexInputStateCreateInfo *vertexInputState)
165 {
166 if(vertexInputState->flags != 0)
167 {
168 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
169 UNSUPPORTED("vertexInputState->flags");
170 }
171
172 // Temporary in-binding-order representation of buffer strides, to be consumed below
173 // when considering attributes. TODO: unfuse buffers from attributes in backend, is old GL model.
174 uint32_t vertexStrides[MAX_VERTEX_INPUT_BINDINGS];
175 uint32_t instanceStrides[MAX_VERTEX_INPUT_BINDINGS];
176 for(uint32_t i = 0; i < vertexInputState->vertexBindingDescriptionCount; i++)
177 {
178 auto const &desc = vertexInputState->pVertexBindingDescriptions[i];
179 vertexStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_VERTEX ? desc.stride : 0;
180 instanceStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE ? desc.stride : 0;
181 }
182
183 for(uint32_t i = 0; i < vertexInputState->vertexAttributeDescriptionCount; i++)
184 {
185 auto const &desc = vertexInputState->pVertexAttributeDescriptions[i];
186 sw::Stream &input = stream[desc.location];
187 input.format = desc.format;
188 input.offset = desc.offset;
189 input.binding = desc.binding;
190 input.vertexStride = vertexStrides[desc.binding];
191 input.instanceStride = instanceStrides[desc.binding];
192 }
193 }
194
updateDescriptorSets(const DescriptorSet::Array & dso,const DescriptorSet::Bindings & ds,const DescriptorSet::DynamicOffsets & ddo)195 void Inputs::updateDescriptorSets(const DescriptorSet::Array &dso,
196 const DescriptorSet::Bindings &ds,
197 const DescriptorSet::DynamicOffsets &ddo)
198 {
199 descriptorSetObjects = dso;
200 descriptorSets = ds;
201 descriptorDynamicOffsets = ddo;
202 }
203
bindVertexInputs(int firstInstance)204 void Inputs::bindVertexInputs(int firstInstance)
205 {
206 for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
207 {
208 auto &attrib = stream[i];
209 if(attrib.format != VK_FORMAT_UNDEFINED)
210 {
211 const auto &vertexInput = vertexInputBindings[attrib.binding];
212 VkDeviceSize offset = attrib.offset + vertexInput.offset +
213 attrib.instanceStride * firstInstance;
214 attrib.buffer = vertexInput.buffer ? vertexInput.buffer->getOffsetPointer(offset) : nullptr;
215
216 VkDeviceSize size = vertexInput.buffer ? vertexInput.buffer->getSize() : 0;
217 attrib.robustnessSize = (size > offset) ? size - offset : 0;
218 }
219 }
220 }
221
setVertexInputBinding(const VertexInputBinding bindings[])222 void Inputs::setVertexInputBinding(const VertexInputBinding bindings[])
223 {
224 for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; ++i)
225 {
226 vertexInputBindings[i] = bindings[i];
227 }
228 }
229
230 // TODO(b/137740918): Optimize instancing to use a single draw call.
advanceInstanceAttributes()231 void Inputs::advanceInstanceAttributes()
232 {
233 for(uint32_t i = 0; i < vk::MAX_VERTEX_INPUT_BINDINGS; i++)
234 {
235 auto &attrib = stream[i];
236 if((attrib.format != VK_FORMAT_UNDEFINED) && attrib.instanceStride && (attrib.instanceStride < attrib.robustnessSize))
237 {
238 // Under the casts: attrib.buffer += attrib.instanceStride
239 attrib.buffer = (void const *)((uintptr_t)attrib.buffer + attrib.instanceStride);
240 attrib.robustnessSize -= attrib.instanceStride;
241 }
242 }
243 }
244
ParseDynamicStateFlags(const VkPipelineDynamicStateCreateInfo * dynamicStateCreateInfo)245 GraphicsState::DynamicStateFlags GraphicsState::ParseDynamicStateFlags(const VkPipelineDynamicStateCreateInfo *dynamicStateCreateInfo)
246 {
247 GraphicsState::DynamicStateFlags dynamicStateFlags = {};
248
249 if(dynamicStateCreateInfo)
250 {
251 if(dynamicStateCreateInfo->flags != 0)
252 {
253 // Vulkan 1.3: "flags is reserved for future use." "flags must be 0"
254 UNSUPPORTED("dynamicStateCreateInfo->flags %d", int(dynamicStateCreateInfo->flags));
255 }
256
257 for(uint32_t i = 0; i < dynamicStateCreateInfo->dynamicStateCount; i++)
258 {
259 VkDynamicState dynamicState = dynamicStateCreateInfo->pDynamicStates[i];
260 switch(dynamicState)
261 {
262 case VK_DYNAMIC_STATE_VIEWPORT:
263 dynamicStateFlags.dynamicViewport = true;
264 break;
265 case VK_DYNAMIC_STATE_SCISSOR:
266 dynamicStateFlags.dynamicScissor = true;
267 break;
268 case VK_DYNAMIC_STATE_LINE_WIDTH:
269 dynamicStateFlags.dynamicLineWidth = true;
270 break;
271 case VK_DYNAMIC_STATE_DEPTH_BIAS:
272 dynamicStateFlags.dynamicDepthBias = true;
273 break;
274 case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
275 dynamicStateFlags.dynamicBlendConstants = true;
276 break;
277 case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
278 dynamicStateFlags.dynamicDepthBounds = true;
279 break;
280 case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
281 dynamicStateFlags.dynamicStencilCompareMask = true;
282 break;
283 case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
284 dynamicStateFlags.dynamicStencilWriteMask = true;
285 break;
286 case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
287 dynamicStateFlags.dynamicStencilReference = true;
288 break;
289 case VK_DYNAMIC_STATE_CULL_MODE:
290 dynamicStateFlags.dynamicCullMode = true;
291 break;
292 case VK_DYNAMIC_STATE_FRONT_FACE:
293 dynamicStateFlags.dynamicFrontFace = true;
294 break;
295 case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY:
296 dynamicStateFlags.dynamicPrimitiveTopology = true;
297 break;
298 case VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT:
299 dynamicStateFlags.dynamicViewportWithCount = true;
300 break;
301 case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT:
302 dynamicStateFlags.dynamicScissorWithCount = true;
303 break;
304 case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE:
305 dynamicStateFlags.dynamicVertexInputBindingStride = true;
306 break;
307 case VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE:
308 dynamicStateFlags.dynamicDepthTestEnable = true;
309 break;
310 case VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE:
311 dynamicStateFlags.dynamicDepthWriteEnable = true;
312 break;
313 case VK_DYNAMIC_STATE_DEPTH_COMPARE_OP:
314 dynamicStateFlags.dynamicDepthCompareOp = true;
315 break;
316 case VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE:
317 dynamicStateFlags.dynamicDepthBoundsTestEnable = true;
318 break;
319 case VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE:
320 dynamicStateFlags.dynamicStencilTestEnable = true;
321 break;
322 case VK_DYNAMIC_STATE_STENCIL_OP:
323 dynamicStateFlags.dynamicStencilOp = true;
324 break;
325 case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE:
326 dynamicStateFlags.dynamicRasterizerDiscardEnable = true;
327 break;
328 case VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE:
329 dynamicStateFlags.dynamicDepthBiasEnable = true;
330 break;
331 case VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE:
332 dynamicStateFlags.dynamicPrimitiveRestartEnable = true;
333 break;
334 default:
335 UNSUPPORTED("VkDynamicState %d", int(dynamicState));
336 }
337 }
338 }
339
340 return dynamicStateFlags;
341 }
342
getVertexStride(uint32_t i,bool dynamicVertexStride) const343 VkDeviceSize Inputs::getVertexStride(uint32_t i, bool dynamicVertexStride) const
344 {
345 auto &attrib = stream[i];
346 if(attrib.format != VK_FORMAT_UNDEFINED)
347 {
348 if(dynamicVertexStride)
349 {
350 return vertexInputBindings[attrib.binding].stride;
351 }
352 else
353 {
354 return attrib.vertexStride;
355 }
356 }
357
358 return 0;
359 }
360
GraphicsState(const Device * device,const VkGraphicsPipelineCreateInfo * pCreateInfo,const PipelineLayout * layout,bool robustBufferAccess)361 GraphicsState::GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo,
362 const PipelineLayout *layout, bool robustBufferAccess)
363 : pipelineLayout(layout)
364 , robustBufferAccess(robustBufferAccess)
365 , dynamicStateFlags(ParseDynamicStateFlags(pCreateInfo->pDynamicState))
366 {
367 if((pCreateInfo->flags &
368 ~(VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT |
369 VK_PIPELINE_CREATE_DERIVATIVE_BIT |
370 VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT |
371 VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT |
372 VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT)) != 0)
373 {
374 UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
375 }
376
377 const VkPipelineVertexInputStateCreateInfo *vertexInputState = pCreateInfo->pVertexInputState;
378
379 if(vertexInputState->flags != 0)
380 {
381 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
382 UNSUPPORTED("vertexInputState->flags");
383 }
384
385 const VkPipelineInputAssemblyStateCreateInfo *inputAssemblyState = pCreateInfo->pInputAssemblyState;
386
387 if(inputAssemblyState->flags != 0)
388 {
389 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
390 UNSUPPORTED("pCreateInfo->pInputAssemblyState->flags %d", int(pCreateInfo->pInputAssemblyState->flags));
391 }
392
393 primitiveRestartEnable = (inputAssemblyState->primitiveRestartEnable != VK_FALSE);
394 topology = inputAssemblyState->topology;
395
396 const VkPipelineRasterizationStateCreateInfo *rasterizationState = pCreateInfo->pRasterizationState;
397
398 if(rasterizationState->flags != 0)
399 {
400 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
401 UNSUPPORTED("pCreateInfo->pRasterizationState->flags %d", int(pCreateInfo->pRasterizationState->flags));
402 }
403
404 rasterizerDiscard = (rasterizationState->rasterizerDiscardEnable != VK_FALSE);
405 cullMode = rasterizationState->cullMode;
406 frontFace = rasterizationState->frontFace;
407 polygonMode = rasterizationState->polygonMode;
408 depthBiasEnable = rasterizationState->depthBiasEnable;
409 constantDepthBias = rasterizationState->depthBiasConstantFactor;
410 slopeDepthBias = rasterizationState->depthBiasSlopeFactor;
411 depthBiasClamp = rasterizationState->depthBiasClamp;
412 depthRangeUnrestricted = device->hasExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
413 depthClampEnable = rasterizationState->depthClampEnable != VK_FALSE;
414 depthClipEnable = !depthClampEnable;
415
416 // From the Vulkan spec for vkCmdSetDepthBias:
417 // The bias value O for a polygon is:
418 // O = dbclamp(...)
419 // where dbclamp(x) =
420 // * x depthBiasClamp = 0 or NaN
421 // * min(x, depthBiasClamp) depthBiasClamp > 0
422 // * max(x, depthBiasClamp) depthBiasClamp < 0
423 // So it should be safe to resolve NaNs to 0.0f.
424 if(std::isnan(depthBiasClamp))
425 {
426 depthBiasClamp = 0.0f;
427 }
428
429 lineWidth = rasterizationState->lineWidth;
430
431 const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(rasterizationState->pNext);
432 while(extensionCreateInfo)
433 {
434 switch(extensionCreateInfo->sType)
435 {
436 case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT:
437 {
438 const VkPipelineRasterizationLineStateCreateInfoEXT *lineStateCreateInfo = reinterpret_cast<const VkPipelineRasterizationLineStateCreateInfoEXT *>(extensionCreateInfo);
439 lineRasterizationMode = lineStateCreateInfo->lineRasterizationMode;
440 }
441 break;
442 case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT:
443 {
444 const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *provokingVertexModeCreateInfo =
445 reinterpret_cast<const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *>(extensionCreateInfo);
446 provokingVertexMode = provokingVertexModeCreateInfo->provokingVertexMode;
447 }
448 break;
449 case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT:
450 {
451 const auto *depthClipInfo = reinterpret_cast<const VkPipelineRasterizationDepthClipStateCreateInfoEXT *>(extensionCreateInfo);
452 // Reserved for future use.
453 ASSERT(depthClipInfo->flags == 0);
454 depthClipEnable = depthClipInfo->depthClipEnable != VK_FALSE;
455 }
456 break;
457 case VK_STRUCTURE_TYPE_APPLICATION_INFO:
458 // SwiftShader doesn't interact with application info, but dEQP includes it
459 break;
460 case VK_STRUCTURE_TYPE_MAX_ENUM:
461 // dEQP tests that this value is ignored.
462 break;
463 default:
464 UNSUPPORTED("pCreateInfo->pRasterizationState->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());
465 break;
466 }
467
468 extensionCreateInfo = extensionCreateInfo->pNext;
469 }
470
471 // The sample count affects the batch size, so it needs initialization even if rasterization is disabled.
472 // TODO(b/147812380): Eliminate the dependency between multisampling and batch size.
473 sampleCount = 1;
474
475 // Only access rasterization state if rasterization is not disabled.
476 if(rasterizationState->rasterizerDiscardEnable == VK_FALSE)
477 {
478 const VkPipelineViewportStateCreateInfo *viewportState = pCreateInfo->pViewportState;
479 const VkPipelineMultisampleStateCreateInfo *multisampleState = pCreateInfo->pMultisampleState;
480 const VkPipelineDepthStencilStateCreateInfo *depthStencilState = pCreateInfo->pDepthStencilState;
481 const VkPipelineColorBlendStateCreateInfo *colorBlendState = pCreateInfo->pColorBlendState;
482
483 if(viewportState->flags != 0)
484 {
485 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
486 UNSUPPORTED("pCreateInfo->pViewportState->flags %d", int(pCreateInfo->pViewportState->flags));
487 }
488
489 if((viewportState->viewportCount > 1) ||
490 (viewportState->scissorCount > 1))
491 {
492 UNSUPPORTED("VkPhysicalDeviceFeatures::multiViewport");
493 }
494
495 if(!dynamicStateFlags.dynamicScissor && !dynamicStateFlags.dynamicScissorWithCount)
496 {
497 scissor = viewportState->pScissors[0];
498 }
499
500 if(!dynamicStateFlags.dynamicViewport && !dynamicStateFlags.dynamicViewportWithCount)
501 {
502 viewport = viewportState->pViewports[0];
503 }
504
505 if(multisampleState->flags != 0)
506 {
507 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
508 UNSUPPORTED("pCreateInfo->pMultisampleState->flags %d", int(pCreateInfo->pMultisampleState->flags));
509 }
510
511 sampleShadingEnable = (multisampleState->sampleShadingEnable != VK_FALSE);
512 if(sampleShadingEnable)
513 {
514 minSampleShading = multisampleState->minSampleShading;
515 }
516
517 if(multisampleState->alphaToOneEnable != VK_FALSE)
518 {
519 UNSUPPORTED("VkPhysicalDeviceFeatures::alphaToOne");
520 }
521
522 switch(multisampleState->rasterizationSamples)
523 {
524 case VK_SAMPLE_COUNT_1_BIT:
525 sampleCount = 1;
526 break;
527 case VK_SAMPLE_COUNT_4_BIT:
528 sampleCount = 4;
529 break;
530 default:
531 UNSUPPORTED("Unsupported sample count");
532 }
533
534 VkSampleMask sampleMask;
535 if(multisampleState->pSampleMask)
536 {
537 sampleMask = multisampleState->pSampleMask[0];
538 }
539 else // "If pSampleMask is NULL, it is treated as if the mask has all bits set to 1."
540 {
541 sampleMask = ~0;
542 }
543
544 alphaToCoverage = (multisampleState->alphaToCoverageEnable != VK_FALSE);
545 multiSampleMask = sampleMask & ((unsigned)0xFFFFFFFF >> (32 - sampleCount));
546
547 const vk::RenderPass *renderPass = vk::Cast(pCreateInfo->renderPass);
548 if(renderPass)
549 {
550 const VkSubpassDescription &subpass = renderPass->getSubpass(pCreateInfo->subpass);
551
552 // Ignore pDepthStencilState when "the subpass of the render pass the pipeline
553 // is created against does not use a depth/stencil attachment"
554 if(subpass.pDepthStencilAttachment &&
555 subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
556 {
557 setDepthStencilState(depthStencilState);
558 }
559
560 // Ignore pColorBlendState when "the subpass of the render pass the pipeline
561 // is created against does not use any color attachments"
562 for(uint32_t i = 0; i < subpass.colorAttachmentCount; i++)
563 {
564 if(subpass.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED)
565 {
566 setColorBlendState(colorBlendState);
567 break;
568 }
569 }
570 }
571 else // No render pass
572 {
573 // When a pipeline is created without a VkRenderPass, if the VkPipelineRenderingCreateInfo structure
574 // is present in the pNext chain of VkGraphicsPipelineCreateInfo, it specifies the view mask and
575 // format of attachments used for rendering. If this structure is not specified, and the pipeline
576 // does not include a VkRenderPass, viewMask and colorAttachmentCount are 0, and
577 // depthAttachmentFormat and stencilAttachmentFormat are VK_FORMAT_UNDEFINED. If a graphics pipeline
578 // is created with a valid VkRenderPass, parameters of this structure are ignored.
579
580 const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
581 while(extensionCreateInfo)
582 {
583 if(extensionCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO)
584 {
585 const VkPipelineRenderingCreateInfo *renderingCreateInfo = reinterpret_cast<const VkPipelineRenderingCreateInfo *>(extensionCreateInfo);
586
587 if((renderingCreateInfo->depthAttachmentFormat != VK_FORMAT_UNDEFINED) ||
588 (renderingCreateInfo->stencilAttachmentFormat != VK_FORMAT_UNDEFINED))
589 {
590 // If renderPass is VK_NULL_HANDLE, the pipeline is being created with fragment
591 // shader state, and either of VkPipelineRenderingCreateInfo::depthAttachmentFormat
592 // or VkPipelineRenderingCreateInfo::stencilAttachmentFormat are not
593 // VK_FORMAT_UNDEFINED, pDepthStencilState must be a valid pointer to a valid
594 // VkPipelineDepthStencilStateCreateInfo structure
595 ASSERT(depthStencilState);
596
597 setDepthStencilState(depthStencilState);
598 }
599
600 if(renderingCreateInfo->colorAttachmentCount > 0)
601 {
602 // If renderPass is VK_NULL_HANDLE, the pipeline is being created with fragment
603 // output interface state, and VkPipelineRenderingCreateInfo::colorAttachmentCount
604 // is not equal to 0, pColorBlendState must be a valid pointer to a valid
605 // VkPipelineColorBlendStateCreateInfo structure
606 ASSERT(colorBlendState);
607
608 setColorBlendState(colorBlendState);
609 }
610
611 break;
612 }
613
614 extensionCreateInfo = extensionCreateInfo->pNext;
615 }
616 }
617 }
618 }
619
setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo * depthStencilState)620 void GraphicsState::setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo *depthStencilState)
621 {
622 if(depthStencilState->flags != 0)
623 {
624 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
625 UNSUPPORTED("depthStencilState->flags %d", int(depthStencilState->flags));
626 }
627
628 depthBoundsTestEnable = (depthStencilState->depthBoundsTestEnable != VK_FALSE);
629 minDepthBounds = depthStencilState->minDepthBounds;
630 maxDepthBounds = depthStencilState->maxDepthBounds;
631
632 depthTestEnable = (depthStencilState->depthTestEnable != VK_FALSE);
633 depthWriteEnable = (depthStencilState->depthWriteEnable != VK_FALSE);
634 depthCompareMode = depthStencilState->depthCompareOp;
635
636 stencilEnable = (depthStencilState->stencilTestEnable != VK_FALSE);
637 if(stencilEnable)
638 {
639 frontStencil = depthStencilState->front;
640 backStencil = depthStencilState->back;
641 }
642 }
643
setColorBlendState(const VkPipelineColorBlendStateCreateInfo * colorBlendState)644 void GraphicsState::setColorBlendState(const VkPipelineColorBlendStateCreateInfo *colorBlendState)
645 {
646 if(colorBlendState->flags != 0)
647 {
648 // Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
649 UNSUPPORTED("colorBlendState->flags %d", int(colorBlendState->flags));
650 }
651
652 if(colorBlendState->logicOpEnable != VK_FALSE)
653 {
654 UNSUPPORTED("VkPhysicalDeviceFeatures::logicOp");
655 }
656
657 if(!dynamicStateFlags.dynamicBlendConstants)
658 {
659 blendConstants.x = colorBlendState->blendConstants[0];
660 blendConstants.y = colorBlendState->blendConstants[1];
661 blendConstants.z = colorBlendState->blendConstants[2];
662 blendConstants.w = colorBlendState->blendConstants[3];
663 }
664
665 const VkBaseInStructure *extensionColorBlendInfo = reinterpret_cast<const VkBaseInStructure *>(colorBlendState->pNext);
666 while(extensionColorBlendInfo)
667 {
668 switch(extensionColorBlendInfo->sType)
669 {
670 case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT:
671 {
672 const VkPipelineColorBlendAdvancedStateCreateInfoEXT *colorBlendAdvancedCreateInfo = reinterpret_cast<const VkPipelineColorBlendAdvancedStateCreateInfoEXT *>(extensionColorBlendInfo);
673 ASSERT(colorBlendAdvancedCreateInfo->blendOverlap == VK_BLEND_OVERLAP_UNCORRELATED_EXT);
674 ASSERT(colorBlendAdvancedCreateInfo->dstPremultiplied == VK_TRUE);
675 ASSERT(colorBlendAdvancedCreateInfo->srcPremultiplied == VK_TRUE);
676 }
677 break;
678 case VK_STRUCTURE_TYPE_MAX_ENUM:
679 // dEQP tests that this value is ignored.
680 break;
681 default:
682 UNSUPPORTED("colorBlendState->pNext sType = %s", vk::Stringify(extensionColorBlendInfo->sType).c_str());
683 break;
684 }
685
686 extensionColorBlendInfo = extensionColorBlendInfo->pNext;
687 }
688
689 ASSERT(colorBlendState->attachmentCount <= sw::MAX_COLOR_BUFFERS);
690 for(auto i = 0u; i < colorBlendState->attachmentCount; i++)
691 {
692 const VkPipelineColorBlendAttachmentState &attachment = colorBlendState->pAttachments[i];
693 colorWriteMask[i] = attachment.colorWriteMask;
694 blendState[i] = { (attachment.blendEnable != VK_FALSE),
695 attachment.srcColorBlendFactor, attachment.dstColorBlendFactor, attachment.colorBlendOp,
696 attachment.srcAlphaBlendFactor, attachment.dstAlphaBlendFactor, attachment.alphaBlendOp };
697 }
698 }
699
isDrawPoint(bool polygonModeAware) const700 bool GraphicsState::isDrawPoint(bool polygonModeAware) const
701 {
702 switch(topology)
703 {
704 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
705 return true;
706 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
707 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
708 return false;
709 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
710 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
711 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
712 return polygonModeAware ? (polygonMode == VK_POLYGON_MODE_POINT) : false;
713 default:
714 UNSUPPORTED("topology %d", int(topology));
715 }
716 return false;
717 }
718
isDrawLine(bool polygonModeAware) const719 bool GraphicsState::isDrawLine(bool polygonModeAware) const
720 {
721 switch(topology)
722 {
723 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
724 return false;
725 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
726 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
727 return true;
728 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
729 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
730 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
731 return polygonModeAware ? (polygonMode == VK_POLYGON_MODE_LINE) : false;
732 default:
733 UNSUPPORTED("topology %d", int(topology));
734 }
735 return false;
736 }
737
isDrawTriangle(bool polygonModeAware) const738 bool GraphicsState::isDrawTriangle(bool polygonModeAware) const
739 {
740 switch(topology)
741 {
742 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
743 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
744 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
745 return false;
746 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
747 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
748 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
749 return polygonModeAware ? (polygonMode == VK_POLYGON_MODE_FILL) : true;
750 default:
751 UNSUPPORTED("topology %d", int(topology));
752 }
753 return false;
754 }
755
depthWriteActive(const Attachments & attachments) const756 bool GraphicsState::depthWriteActive(const Attachments &attachments) const
757 {
758 // "Depth writes are always disabled when depthTestEnable is VK_FALSE."
759 return depthTestActive(attachments) && depthWriteEnable;
760 }
761
depthTestActive(const Attachments & attachments) const762 bool GraphicsState::depthTestActive(const Attachments &attachments) const
763 {
764 return attachments.depthBuffer && depthTestEnable;
765 }
766
stencilActive(const Attachments & attachments) const767 bool GraphicsState::stencilActive(const Attachments &attachments) const
768 {
769 return attachments.stencilBuffer && stencilEnable;
770 }
771
depthBoundsTestActive(const Attachments & attachments) const772 bool GraphicsState::depthBoundsTestActive(const Attachments &attachments) const
773 {
774 return attachments.depthBuffer && depthBoundsTestEnable;
775 }
776
combineStates(const DynamicState & dynamicState) const777 const GraphicsState GraphicsState::combineStates(const DynamicState &dynamicState) const
778 {
779 GraphicsState combinedState = *this;
780
781 // Apply either pipeline state or dynamic state
782 if(dynamicStateFlags.dynamicDepthTestEnable)
783 {
784 combinedState.depthTestEnable = dynamicState.depthTestEnable;
785 }
786
787 if(dynamicStateFlags.dynamicDepthWriteEnable)
788 {
789 combinedState.depthWriteEnable = dynamicState.depthWriteEnable;
790 }
791
792 if(dynamicStateFlags.dynamicDepthCompareOp)
793 {
794 combinedState.depthCompareMode = dynamicState.depthCompareOp;
795 }
796
797 if(dynamicStateFlags.dynamicDepthBoundsTestEnable)
798 {
799 combinedState.depthBoundsTestEnable = dynamicState.depthBoundsTestEnable;
800 }
801
802 if(dynamicStateFlags.dynamicStencilTestEnable)
803 {
804 combinedState.stencilEnable = dynamicState.stencilTestEnable;
805 }
806
807 if(dynamicStateFlags.dynamicRasterizerDiscardEnable)
808 {
809 combinedState.rasterizerDiscard = dynamicState.rasterizerDiscardEnable;
810 }
811
812 if(dynamicStateFlags.dynamicDepthBiasEnable)
813 {
814 combinedState.depthBiasEnable = dynamicState.depthBiasEnable;
815 }
816
817 if(dynamicStateFlags.dynamicPrimitiveRestartEnable)
818 {
819 combinedState.primitiveRestartEnable = dynamicState.primitiveRestartEnable;
820 }
821
822 if(dynamicStateFlags.dynamicScissor)
823 {
824 combinedState.scissor = dynamicState.scissor;
825 }
826
827 if(dynamicStateFlags.dynamicViewport)
828 {
829 combinedState.viewport = dynamicState.viewport;
830 }
831
832 if(dynamicStateFlags.dynamicBlendConstants)
833 {
834 combinedState.blendConstants = dynamicState.blendConstants;
835 }
836
837 if(dynamicStateFlags.dynamicDepthBias)
838 {
839 combinedState.constantDepthBias = dynamicState.depthBiasConstantFactor;
840 combinedState.slopeDepthBias = dynamicState.depthBiasSlopeFactor;
841 combinedState.depthBiasClamp = dynamicState.depthBiasClamp;
842 }
843
844 if(dynamicStateFlags.dynamicDepthBounds && combinedState.depthBoundsTestEnable)
845 {
846 combinedState.minDepthBounds = dynamicState.minDepthBounds;
847 combinedState.maxDepthBounds = dynamicState.maxDepthBounds;
848 }
849
850 if(dynamicStateFlags.dynamicStencilCompareMask && combinedState.stencilEnable)
851 {
852 combinedState.frontStencil.compareMask = dynamicState.frontStencil.compareMask;
853 combinedState.backStencil.compareMask = dynamicState.backStencil.compareMask;
854 }
855
856 if(dynamicStateFlags.dynamicStencilWriteMask && combinedState.stencilEnable)
857 {
858 combinedState.frontStencil.writeMask = dynamicState.frontStencil.writeMask;
859 combinedState.backStencil.writeMask = dynamicState.backStencil.writeMask;
860 }
861
862 if(dynamicStateFlags.dynamicStencilReference && combinedState.stencilEnable)
863 {
864 combinedState.frontStencil.reference = dynamicState.frontStencil.reference;
865 combinedState.backStencil.reference = dynamicState.backStencil.reference;
866 }
867
868 if(dynamicStateFlags.dynamicStencilOp && combinedState.stencilEnable)
869 {
870 if(dynamicState.faceMask & VK_STENCIL_FACE_FRONT_BIT)
871 {
872 combinedState.frontStencil.compareOp = dynamicState.frontStencil.compareOp;
873 combinedState.frontStencil.depthFailOp = dynamicState.frontStencil.depthFailOp;
874 combinedState.frontStencil.failOp = dynamicState.frontStencil.failOp;
875 combinedState.frontStencil.passOp = dynamicState.frontStencil.passOp;
876 }
877
878 if(dynamicState.faceMask & VK_STENCIL_FACE_BACK_BIT)
879 {
880 combinedState.backStencil.compareOp = dynamicState.backStencil.compareOp;
881 combinedState.backStencil.depthFailOp = dynamicState.backStencil.depthFailOp;
882 combinedState.backStencil.failOp = dynamicState.backStencil.failOp;
883 combinedState.backStencil.passOp = dynamicState.backStencil.passOp;
884 }
885 }
886
887 if(dynamicStateFlags.dynamicCullMode)
888 {
889 combinedState.cullMode = dynamicState.cullMode;
890 }
891
892 if(dynamicStateFlags.dynamicFrontFace)
893 {
894 combinedState.frontFace = dynamicState.frontFace;
895 }
896
897 if(dynamicStateFlags.dynamicPrimitiveTopology)
898 {
899 combinedState.topology = dynamicState.primitiveTopology;
900 }
901
902 if(dynamicStateFlags.dynamicViewportWithCount && (dynamicState.viewportCount > 0))
903 {
904 combinedState.viewport.width = static_cast<float>(dynamicState.viewports[0].extent.width);
905 combinedState.viewport.height = static_cast<float>(dynamicState.viewports[0].extent.height);
906 combinedState.viewport.x = static_cast<float>(dynamicState.viewports[0].offset.x);
907 combinedState.viewport.y = static_cast<float>(dynamicState.viewports[0].offset.y);
908 }
909
910 if(dynamicStateFlags.dynamicScissorWithCount && (dynamicState.scissorCount > 0))
911 {
912 combinedState.scissor = dynamicState.scissors[0];
913 }
914
915 return combinedState;
916 }
917
getBlendState(int index,const Attachments & attachments,bool fragmentContainsKill) const918 BlendState GraphicsState::getBlendState(int index, const Attachments &attachments, bool fragmentContainsKill) const
919 {
920 ASSERT((index >= 0) && (index < sw::MAX_COLOR_BUFFERS));
921 auto &state = blendState[index];
922
923 BlendState activeBlendState = {};
924 activeBlendState.alphaBlendEnable = alphaBlendActive(index, attachments, fragmentContainsKill);
925
926 if(activeBlendState.alphaBlendEnable)
927 {
928 vk::Format format = attachments.colorBuffer[index]->getFormat(VK_IMAGE_ASPECT_COLOR_BIT);
929
930 activeBlendState.sourceBlendFactor = blendFactor(state.blendOperation, state.sourceBlendFactor);
931 activeBlendState.destBlendFactor = blendFactor(state.blendOperation, state.destBlendFactor);
932 activeBlendState.blendOperation = blendOperation(state.blendOperation, state.sourceBlendFactor, state.destBlendFactor, format);
933 activeBlendState.sourceBlendFactorAlpha = blendFactor(state.blendOperationAlpha, state.sourceBlendFactorAlpha);
934 activeBlendState.destBlendFactorAlpha = blendFactor(state.blendOperationAlpha, state.destBlendFactorAlpha);
935 activeBlendState.blendOperationAlpha = blendOperation(state.blendOperationAlpha, state.sourceBlendFactorAlpha, state.destBlendFactorAlpha, format);
936 }
937
938 return activeBlendState;
939 }
940
alphaBlendActive(int index,const Attachments & attachments,bool fragmentContainsKill) const941 bool GraphicsState::alphaBlendActive(int index, const Attachments &attachments, bool fragmentContainsKill) const
942 {
943 ASSERT((index >= 0) && (index < sw::MAX_COLOR_BUFFERS));
944 auto &state = blendState[index];
945
946 if(!attachments.colorBuffer[index] || !blendState[index].alphaBlendEnable)
947 {
948 return false;
949 }
950
951 if(!(colorWriteActive(attachments) || fragmentContainsKill))
952 {
953 return false;
954 }
955
956 vk::Format format = attachments.colorBuffer[index]->getFormat(VK_IMAGE_ASPECT_COLOR_BIT);
957 bool colorBlend = blendOperation(state.blendOperation, state.sourceBlendFactor, state.destBlendFactor, format) != VK_BLEND_OP_SRC_EXT;
958 bool alphaBlend = blendOperation(state.blendOperationAlpha, state.sourceBlendFactorAlpha, state.destBlendFactorAlpha, format) != VK_BLEND_OP_SRC_EXT;
959
960 return colorBlend || alphaBlend;
961 }
962
blendFactor(VkBlendOp blendOperation,VkBlendFactor blendFactor) const963 VkBlendFactor GraphicsState::blendFactor(VkBlendOp blendOperation, VkBlendFactor blendFactor) const
964 {
965 switch(blendOperation)
966 {
967 case VK_BLEND_OP_ADD:
968 case VK_BLEND_OP_SUBTRACT:
969 case VK_BLEND_OP_REVERSE_SUBTRACT:
970 return blendFactor;
971 case VK_BLEND_OP_MIN:
972 case VK_BLEND_OP_MAX:
973 case VK_BLEND_OP_MULTIPLY_EXT:
974 case VK_BLEND_OP_SCREEN_EXT:
975 case VK_BLEND_OP_OVERLAY_EXT:
976 case VK_BLEND_OP_DARKEN_EXT:
977 case VK_BLEND_OP_LIGHTEN_EXT:
978 case VK_BLEND_OP_COLORDODGE_EXT:
979 case VK_BLEND_OP_COLORBURN_EXT:
980 case VK_BLEND_OP_HARDLIGHT_EXT:
981 case VK_BLEND_OP_SOFTLIGHT_EXT:
982 case VK_BLEND_OP_DIFFERENCE_EXT:
983 case VK_BLEND_OP_EXCLUSION_EXT:
984 case VK_BLEND_OP_HSL_HUE_EXT:
985 case VK_BLEND_OP_HSL_SATURATION_EXT:
986 case VK_BLEND_OP_HSL_COLOR_EXT:
987 case VK_BLEND_OP_HSL_LUMINOSITY_EXT:
988 return VK_BLEND_FACTOR_ONE;
989 default:
990 ASSERT(false);
991 return blendFactor;
992 }
993 }
994
blendOperation(VkBlendOp blendOperation,VkBlendFactor sourceBlendFactor,VkBlendFactor destBlendFactor,vk::Format format) const995 VkBlendOp GraphicsState::blendOperation(VkBlendOp blendOperation, VkBlendFactor sourceBlendFactor, VkBlendFactor destBlendFactor, vk::Format format) const
996 {
997 switch(blendOperation)
998 {
999 case VK_BLEND_OP_ADD:
1000 if(sourceBlendFactor == VK_BLEND_FACTOR_ZERO)
1001 {
1002 if(destBlendFactor == VK_BLEND_FACTOR_ZERO)
1003 {
1004 return VK_BLEND_OP_ZERO_EXT;
1005 }
1006 else if(destBlendFactor == VK_BLEND_FACTOR_ONE)
1007 {
1008 return VK_BLEND_OP_DST_EXT;
1009 }
1010 }
1011 else if(sourceBlendFactor == VK_BLEND_FACTOR_ONE)
1012 {
1013 if(destBlendFactor == VK_BLEND_FACTOR_ZERO)
1014 {
1015 return VK_BLEND_OP_SRC_EXT;
1016 }
1017 }
1018 break;
1019 case VK_BLEND_OP_SUBTRACT:
1020 if(sourceBlendFactor == VK_BLEND_FACTOR_ZERO)
1021 {
1022 if(destBlendFactor == VK_BLEND_FACTOR_ZERO)
1023 {
1024 return VK_BLEND_OP_ZERO_EXT;
1025 }
1026 else if(format.isUnsignedNormalized())
1027 {
1028 return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
1029 }
1030 }
1031 else if(sourceBlendFactor == VK_BLEND_FACTOR_ONE)
1032 {
1033 if(destBlendFactor == VK_BLEND_FACTOR_ZERO)
1034 {
1035 return VK_BLEND_OP_SRC_EXT;
1036 }
1037 }
1038 break;
1039 case VK_BLEND_OP_REVERSE_SUBTRACT:
1040 if(sourceBlendFactor == VK_BLEND_FACTOR_ZERO)
1041 {
1042 if(destBlendFactor == VK_BLEND_FACTOR_ZERO)
1043 {
1044 return VK_BLEND_OP_ZERO_EXT;
1045 }
1046 else if(destBlendFactor == VK_BLEND_FACTOR_ONE)
1047 {
1048 return VK_BLEND_OP_DST_EXT;
1049 }
1050 }
1051 else
1052 {
1053 if(destBlendFactor == VK_BLEND_FACTOR_ZERO && format.isUnsignedNormalized())
1054 {
1055 return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
1056 }
1057 }
1058 break;
1059 case VK_BLEND_OP_MIN:
1060 return VK_BLEND_OP_MIN;
1061 case VK_BLEND_OP_MAX:
1062 return VK_BLEND_OP_MAX;
1063 case VK_BLEND_OP_MULTIPLY_EXT:
1064 case VK_BLEND_OP_SCREEN_EXT:
1065 case VK_BLEND_OP_OVERLAY_EXT:
1066 case VK_BLEND_OP_DARKEN_EXT:
1067 case VK_BLEND_OP_LIGHTEN_EXT:
1068 case VK_BLEND_OP_COLORDODGE_EXT:
1069 case VK_BLEND_OP_COLORBURN_EXT:
1070 case VK_BLEND_OP_HARDLIGHT_EXT:
1071 case VK_BLEND_OP_SOFTLIGHT_EXT:
1072 case VK_BLEND_OP_DIFFERENCE_EXT:
1073 case VK_BLEND_OP_EXCLUSION_EXT:
1074 case VK_BLEND_OP_HSL_HUE_EXT:
1075 case VK_BLEND_OP_HSL_SATURATION_EXT:
1076 case VK_BLEND_OP_HSL_COLOR_EXT:
1077 case VK_BLEND_OP_HSL_LUMINOSITY_EXT:
1078 return blendOperation;
1079 default:
1080 ASSERT(false);
1081 }
1082
1083 return blendOperation;
1084 }
1085
colorWriteActive(const Attachments & attachments) const1086 bool GraphicsState::colorWriteActive(const Attachments &attachments) const
1087 {
1088 for(int i = 0; i < sw::MAX_COLOR_BUFFERS; i++)
1089 {
1090 if(colorWriteActive(i, attachments))
1091 {
1092 return true;
1093 }
1094 }
1095
1096 return false;
1097 }
1098
colorWriteActive(int index,const Attachments & attachments) const1099 int GraphicsState::colorWriteActive(int index, const Attachments &attachments) const
1100 {
1101 ASSERT((index >= 0) && (index < sw::MAX_COLOR_BUFFERS));
1102 auto &state = blendState[index];
1103
1104 if(!attachments.colorBuffer[index] || attachments.colorBuffer[index]->getFormat() == VK_FORMAT_UNDEFINED)
1105 {
1106 return 0;
1107 }
1108
1109 vk::Format format = attachments.colorBuffer[index]->getFormat(VK_IMAGE_ASPECT_COLOR_BIT);
1110
1111 if(blendOperation(state.blendOperation, state.sourceBlendFactor, state.destBlendFactor, format) == VK_BLEND_OP_DST_EXT &&
1112 blendOperation(state.blendOperationAlpha, state.sourceBlendFactorAlpha, state.destBlendFactorAlpha, format) == VK_BLEND_OP_DST_EXT)
1113 {
1114 return 0;
1115 }
1116
1117 return colorWriteMask[index];
1118 }
1119
1120 } // namespace vk