| // Copyright 2017 The Dawn Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "dawn_native/RenderPipeline.h" |
| |
| #include "common/BitSetIterator.h" |
| #include "dawn_native/Device.h" |
| #include "dawn_native/InputState.h" |
| #include "dawn_native/RenderPassDescriptor.h" |
| #include "dawn_native/Texture.h" |
| #include "dawn_native/ValidationUtils_autogen.h" |
| |
| namespace dawn_native { |
| // Helper functions |
| namespace { |
| |
| MaybeError ValidatePipelineStageDescriptor(const PipelineStageDescriptor* descriptor, |
| const PipelineLayoutBase* layout, |
| dawn::ShaderStage stage) { |
| if (descriptor->entryPoint != std::string("main")) { |
| return DAWN_VALIDATION_ERROR("Entry point must be \"main\""); |
| } |
| if (descriptor->module->GetExecutionModel() != stage) { |
| return DAWN_VALIDATION_ERROR("Setting module with wrong stages"); |
| } |
| if (!descriptor->module->IsCompatibleWithPipelineLayout(layout)) { |
| return DAWN_VALIDATION_ERROR("Stage not compatible with layout"); |
| } |
| return {}; |
| } |
| |
| MaybeError ValidateAttachmentsStateDescriptor( |
| const AttachmentsStateDescriptor* descriptor) { |
| if (descriptor->numColorAttachments > kMaxColorAttachments) { |
| return DAWN_VALIDATION_ERROR("Color attachments number exceeds maximum"); |
| } |
| |
| if (descriptor->numColorAttachments == 0 && !descriptor->hasDepthStencilAttachment) { |
| return DAWN_VALIDATION_ERROR("Should have at least one attachment"); |
| } |
| |
| if (descriptor->hasDepthStencilAttachment) { |
| dawn::TextureFormat format = descriptor->depthStencilAttachment->format; |
| DAWN_TRY(ValidateTextureFormat(format)); |
| |
| if (!IsDepthStencilRenderableTextureFormat(format)) { |
| return DAWN_VALIDATION_ERROR( |
| "Depth stencil format must be depth-stencil renderable"); |
| } |
| } |
| |
| for (uint32_t i = 0; i < descriptor->numColorAttachments; ++i) { |
| dawn::TextureFormat format = descriptor->colorAttachments[i]->format; |
| DAWN_TRY(ValidateTextureFormat(format)); |
| |
| if (!IsColorRenderableTextureFormat(format)) { |
| return DAWN_VALIDATION_ERROR("Color format must be color renderable"); |
| } |
| } |
| return {}; |
| } |
| |
| MaybeError ValidateBlendStateDescriptor(const BlendStateDescriptor* descriptor) { |
| if (descriptor->nextInChain != nullptr) { |
| return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); |
| } |
| DAWN_TRY(ValidateBlendOperation(descriptor->alphaBlend.operation)); |
| DAWN_TRY(ValidateBlendFactor(descriptor->alphaBlend.srcFactor)); |
| DAWN_TRY(ValidateBlendFactor(descriptor->alphaBlend.dstFactor)); |
| DAWN_TRY(ValidateBlendOperation(descriptor->colorBlend.operation)); |
| DAWN_TRY(ValidateBlendFactor(descriptor->colorBlend.srcFactor)); |
| DAWN_TRY(ValidateBlendFactor(descriptor->colorBlend.dstFactor)); |
| DAWN_TRY(ValidateColorWriteMask(descriptor->colorWriteMask)); |
| return {}; |
| } |
| |
| MaybeError ValidateDepthStencilStateDescriptor( |
| const DepthStencilStateDescriptor* descriptor) { |
| if (descriptor->nextInChain != nullptr) { |
| return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); |
| } |
| DAWN_TRY(ValidateCompareFunction(descriptor->depthCompare)); |
| DAWN_TRY(ValidateCompareFunction(descriptor->stencilFront.compare)); |
| DAWN_TRY(ValidateStencilOperation(descriptor->stencilFront.failOp)); |
| DAWN_TRY(ValidateStencilOperation(descriptor->stencilFront.depthFailOp)); |
| DAWN_TRY(ValidateStencilOperation(descriptor->stencilFront.passOp)); |
| DAWN_TRY(ValidateCompareFunction(descriptor->stencilBack.compare)); |
| DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.failOp)); |
| DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.depthFailOp)); |
| DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.passOp)); |
| return {}; |
| } |
| |
| } // anonymous namespace |
| |
| MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device, |
| const RenderPipelineDescriptor* descriptor) { |
| if (descriptor->nextInChain != nullptr) { |
| return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); |
| } |
| |
| if (descriptor->layout == nullptr) { |
| return DAWN_VALIDATION_ERROR("Layout must not be null"); |
| } |
| |
| if (descriptor->inputState == nullptr) { |
| return DAWN_VALIDATION_ERROR("Input state must not be null"); |
| } |
| |
| if (descriptor->depthStencilState == nullptr) { |
| return DAWN_VALIDATION_ERROR("Depth stencil state must not be null"); |
| } |
| |
| for (uint32_t i = 0; i < descriptor->numBlendStates; ++i) { |
| DAWN_TRY(ValidateBlendStateDescriptor(&descriptor->blendStates[i])); |
| } |
| |
| DAWN_TRY(ValidateIndexFormat(descriptor->indexFormat)); |
| DAWN_TRY(ValidatePrimitiveTopology(descriptor->primitiveTopology)); |
| DAWN_TRY(ValidatePipelineStageDescriptor(descriptor->vertexStage, descriptor->layout, |
| dawn::ShaderStage::Vertex)); |
| DAWN_TRY(ValidatePipelineStageDescriptor(descriptor->fragmentStage, descriptor->layout, |
| dawn::ShaderStage::Fragment)); |
| DAWN_TRY(ValidateAttachmentsStateDescriptor(descriptor->attachmentsState)); |
| |
| if ((descriptor->vertexStage->module->GetUsedVertexAttributes() & |
| ~descriptor->inputState->GetAttributesSetMask()) |
| .any()) { |
| return DAWN_VALIDATION_ERROR( |
| "Pipeline vertex stage uses inputs not in the input state"); |
| } |
| |
| if (descriptor->sampleCount != 1) { |
| return DAWN_VALIDATION_ERROR("Sample count must be one"); |
| } |
| |
| if (descriptor->numBlendStates > kMaxColorAttachments) { |
| return DAWN_VALIDATION_ERROR("Blend states number exceeds maximum"); |
| } |
| |
| if (descriptor->attachmentsState->numColorAttachments != descriptor->numBlendStates) { |
| return DAWN_VALIDATION_ERROR("Each color attachment should have blend state"); |
| } |
| |
| DAWN_TRY(ValidateDepthStencilStateDescriptor(descriptor->depthStencilState)); |
| |
| return {}; |
| } |
| |
| bool StencilTestEnabled(const DepthStencilStateDescriptor* mDepthStencilState) { |
| return mDepthStencilState->stencilBack.compare != dawn::CompareFunction::Always || |
| mDepthStencilState->stencilBack.failOp != dawn::StencilOperation::Keep || |
| mDepthStencilState->stencilBack.depthFailOp != dawn::StencilOperation::Keep || |
| mDepthStencilState->stencilBack.passOp != dawn::StencilOperation::Keep || |
| mDepthStencilState->stencilFront.compare != dawn::CompareFunction::Always || |
| mDepthStencilState->stencilFront.failOp != dawn::StencilOperation::Keep || |
| mDepthStencilState->stencilFront.depthFailOp != dawn::StencilOperation::Keep || |
| mDepthStencilState->stencilFront.passOp != dawn::StencilOperation::Keep; |
| } |
| |
| // RenderPipelineBase |
| |
| RenderPipelineBase::RenderPipelineBase(DeviceBase* device, |
| const RenderPipelineDescriptor* descriptor) |
| : PipelineBase(device, |
| descriptor->layout, |
| dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment), |
| mDepthStencilState(*descriptor->depthStencilState), |
| mIndexFormat(descriptor->indexFormat), |
| mInputState(descriptor->inputState), |
| mPrimitiveTopology(descriptor->primitiveTopology), |
| mHasDepthStencilAttachment(descriptor->attachmentsState->hasDepthStencilAttachment) { |
| if (mHasDepthStencilAttachment) { |
| mDepthStencilFormat = descriptor->attachmentsState->depthStencilAttachment->format; |
| } |
| ExtractModuleData(dawn::ShaderStage::Vertex, descriptor->vertexStage->module); |
| ExtractModuleData(dawn::ShaderStage::Fragment, descriptor->fragmentStage->module); |
| |
| for (uint32_t i = 0; i < descriptor->attachmentsState->numColorAttachments; ++i) { |
| mColorAttachmentsSet.set(i); |
| mBlendStates[i] = descriptor->blendStates[i]; |
| mColorAttachmentFormats[i] = descriptor->attachmentsState->colorAttachments[i]->format; |
| } |
| |
| // TODO(cwallez@chromium.org): Check against the shader module that the correct color |
| // attachment are set? |
| } |
| |
| const BlendStateDescriptor* RenderPipelineBase::GetBlendStateDescriptor( |
| uint32_t attachmentSlot) { |
| ASSERT(attachmentSlot < mBlendStates.size()); |
| return &mBlendStates[attachmentSlot]; |
| } |
| |
| const DepthStencilStateDescriptor* RenderPipelineBase::GetDepthStencilStateDescriptor() { |
| return &mDepthStencilState; |
| } |
| |
| dawn::IndexFormat RenderPipelineBase::GetIndexFormat() const { |
| return mIndexFormat; |
| } |
| |
| InputStateBase* RenderPipelineBase::GetInputState() { |
| return mInputState.Get(); |
| } |
| |
| dawn::PrimitiveTopology RenderPipelineBase::GetPrimitiveTopology() const { |
| return mPrimitiveTopology; |
| } |
| |
| std::bitset<kMaxColorAttachments> RenderPipelineBase::GetColorAttachmentsMask() const { |
| return mColorAttachmentsSet; |
| } |
| |
| bool RenderPipelineBase::HasDepthStencilAttachment() const { |
| return mHasDepthStencilAttachment; |
| } |
| |
| dawn::TextureFormat RenderPipelineBase::GetColorAttachmentFormat(uint32_t attachment) const { |
| return mColorAttachmentFormats[attachment]; |
| } |
| |
| dawn::TextureFormat RenderPipelineBase::GetDepthStencilFormat() const { |
| ASSERT(mHasDepthStencilAttachment); |
| return mDepthStencilFormat; |
| } |
| |
| bool RenderPipelineBase::IsCompatibleWith(const RenderPassDescriptorBase* renderPass) const { |
| // TODO(cwallez@chromium.org): This is called on every SetPipeline command. Optimize it for |
| // example by caching some "attachment compatibility" object that would make the |
| // compatibility check a single pointer comparison. |
| |
| if (renderPass->GetColorAttachmentMask() != mColorAttachmentsSet) { |
| return false; |
| } |
| |
| for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) { |
| if (renderPass->GetColorAttachment(i).view->GetTexture()->GetFormat() != |
| mColorAttachmentFormats[i]) { |
| return false; |
| } |
| } |
| |
| if (renderPass->HasDepthStencilAttachment() != mHasDepthStencilAttachment) { |
| return false; |
| } |
| |
| if (mHasDepthStencilAttachment && |
| (renderPass->GetDepthStencilAttachment().view->GetTexture()->GetFormat() != |
| mDepthStencilFormat)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } // namespace dawn_native |