void GLGraphicsContext::updateBlendState(const BlendState& blendState) { const BlendState& newState = blendState; const BlendState& currentState = getBlendState(); if (newState.isBlendEnabled() != currentState.isBlendEnabled()) { if (newState.isBlendEnabled()) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } } if (newState.getColorBlendFunction() != currentState.getColorBlendFunction() || newState.getAlphaBlendFunction() != currentState.getAlphaBlendFunction()) { GLenum modeRGB = GLMapping::getBlendFunction(newState.getColorBlendFunction()); GLenum modeAlpha = GLMapping::getBlendFunction(newState.getAlphaBlendFunction()); if (modeRGB == modeAlpha) { glBlendEquation(modeRGB); } else { glBlendEquationSeparate(modeRGB, modeAlpha); } } if (newState.getColorSourceBlend() != currentState.getColorSourceBlend() || newState.getColorDestinationBlend() != currentState.getColorDestinationBlend() || newState.getAlphaSourceBlend() != currentState.getAlphaSourceBlend() || newState.getAlphaDestinationBlend() != currentState.getAlphaDestinationBlend()) { GLenum srcRGB = GLMapping::getSourceBlend(newState.getColorSourceBlend()); GLenum dstRGB = GLMapping::getDestinationBlend(newState.getColorDestinationBlend()); GLenum srcAlpha = GLMapping::getSourceBlend(newState.getAlphaSourceBlend()); GLenum dstAlpha = GLMapping::getDestinationBlend(newState.getAlphaDestinationBlend()); if (srcRGB == srcAlpha && dstRGB == dstAlpha) { glBlendFunc(srcRGB, dstRGB); } else { glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); } } }
void DXDisplay::setBlendState(const std::string id) { if(id != currentBlendState_) { if(id != "") { const auto blendState = getBlendState(id); context_->OMSetBlendState(blendState->blendState, blendState->blendFactor, blendState->sampleMask); } else { const float factor[4] = {0,0,0,0}; context_->OMSetBlendState(nullptr, factor, 0xFFFFFF); } currentBlendState_ = id; } }
void VulkanGraphicsPipelineState::initialize() { Lock(mMutex); GraphicsPipelineState::initialize(); std::pair<VkShaderStageFlagBits, GpuProgram*> stages[] = { { VK_SHADER_STAGE_VERTEX_BIT, mData.vertexProgram.get() }, { VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, mData.hullProgram.get() }, { VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, mData.domainProgram.get() }, { VK_SHADER_STAGE_GEOMETRY_BIT, mData.geometryProgram.get() }, { VK_SHADER_STAGE_FRAGMENT_BIT, mData.fragmentProgram.get() } }; UINT32 stageOutputIdx = 0; UINT32 numStages = sizeof(stages) / sizeof(stages[0]); for(UINT32 i = 0; i < numStages; i++) { VulkanGpuProgram* program = static_cast<VulkanGpuProgram*>(stages[i].second); if (program == nullptr) continue; VkPipelineShaderStageCreateInfo& stageCI = mShaderStageInfos[stageOutputIdx]; stageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stageCI.pNext = nullptr; stageCI.flags = 0; stageCI.stage = stages[i].first; stageCI.module = VK_NULL_HANDLE; stageCI.pName = program->getProperties().getEntryPoint().c_str(); stageCI.pSpecializationInfo = nullptr; stageOutputIdx++; } UINT32 numUsedStages = stageOutputIdx; bool tesselationEnabled = mData.hullProgram != nullptr && mData.domainProgram != nullptr; mInputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; mInputAssemblyInfo.pNext = nullptr; mInputAssemblyInfo.flags = 0; mInputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // Assigned at runtime mInputAssemblyInfo.primitiveRestartEnable = false; mTesselationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; mTesselationInfo.pNext = nullptr; mTesselationInfo.flags = 0; mTesselationInfo.patchControlPoints = 3; // Assigned at runtime mViewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; mViewportInfo.pNext = nullptr; mViewportInfo.flags = 0; mViewportInfo.viewportCount = 1; // Spec says this need to be at least 1... mViewportInfo.scissorCount = 1; mViewportInfo.pViewports = nullptr; // Dynamic mViewportInfo.pScissors = nullptr; // Dynamic RasterizerState* rasterizerState = getRasterizerState().get(); if (rasterizerState == nullptr) rasterizerState = RasterizerState::getDefault().get(); BlendState* blendState = getBlendState().get(); if (blendState == nullptr) blendState = BlendState::getDefault().get(); DepthStencilState* depthStencilState = getDepthStencilState().get(); if (depthStencilState == nullptr) depthStencilState = DepthStencilState::getDefault().get(); const RasterizerProperties& rstProps = rasterizerState->getProperties(); const BlendProperties& blendProps = blendState->getProperties(); const DepthStencilProperties dsProps = depthStencilState->getProperties(); mRasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; mRasterizationInfo.pNext = nullptr; mRasterizationInfo.flags = 0; mRasterizationInfo.depthClampEnable = !rstProps.getDepthClipEnable(); mRasterizationInfo.rasterizerDiscardEnable = VK_FALSE; mRasterizationInfo.polygonMode = VulkanUtility::getPolygonMode(rstProps.getPolygonMode()); mRasterizationInfo.cullMode = VulkanUtility::getCullMode(rstProps.getCullMode()); mRasterizationInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; mRasterizationInfo.depthBiasEnable = rstProps.getDepthBias() != 0.0f; mRasterizationInfo.depthBiasConstantFactor = rstProps.getDepthBias(); mRasterizationInfo.depthBiasSlopeFactor = rstProps.getSlopeScaledDepthBias(); mRasterizationInfo.depthBiasClamp = mRasterizationInfo.depthClampEnable ? rstProps.getDepthBiasClamp() : 0.0f; mRasterizationInfo.lineWidth = 1.0f; mMultiSampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; mMultiSampleInfo.pNext = nullptr; mMultiSampleInfo.flags = 0; mMultiSampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; // Assigned at runtime mMultiSampleInfo.sampleShadingEnable = VK_FALSE; // When enabled, perform shading per sample instead of per pixel (more expensive, essentially FSAA) mMultiSampleInfo.minSampleShading = 1.0f; // Minimum percent of samples to run full shading for when sampleShadingEnable is enabled (1.0f to run for all) mMultiSampleInfo.pSampleMask = nullptr; // Normally one bit for each sample: e.g. 0x0000000F to enable all samples in a 4-sample setup mMultiSampleInfo.alphaToCoverageEnable = blendProps.getAlphaToCoverageEnabled(); mMultiSampleInfo.alphaToOneEnable = VK_FALSE; VkStencilOpState stencilFrontInfo; stencilFrontInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilFrontCompFunc()); stencilFrontInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontZFailOp()); stencilFrontInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontPassOp()); stencilFrontInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontFailOp()); stencilFrontInfo.reference = 0; // Dynamic stencilFrontInfo.compareMask = (UINT32)dsProps.getStencilReadMask(); stencilFrontInfo.writeMask = (UINT32)dsProps.getStencilWriteMask(); VkStencilOpState stencilBackInfo; stencilBackInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilBackCompFunc()); stencilBackInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilBackZFailOp()); stencilBackInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilBackPassOp()); stencilBackInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilBackFailOp()); stencilBackInfo.reference = 0; // Dynamic stencilBackInfo.compareMask = (UINT32)dsProps.getStencilReadMask(); stencilBackInfo.writeMask = (UINT32)dsProps.getStencilWriteMask(); mDepthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; mDepthStencilInfo.pNext = nullptr; mDepthStencilInfo.flags = 0; mDepthStencilInfo.depthBoundsTestEnable = false; mDepthStencilInfo.minDepthBounds = 0.0f; mDepthStencilInfo.maxDepthBounds = 1.0f; mDepthStencilInfo.depthTestEnable = dsProps.getDepthReadEnable(); mDepthStencilInfo.depthWriteEnable = dsProps.getDepthWriteEnable(); mDepthStencilInfo.depthCompareOp = VulkanUtility::getCompareOp(dsProps.getDepthComparisonFunc()); mDepthStencilInfo.front = stencilFrontInfo; mDepthStencilInfo.back = stencilBackInfo; mDepthStencilInfo.stencilTestEnable = dsProps.getStencilEnable(); for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++) { UINT32 rtIdx = 0; if (blendProps.getIndependantBlendEnable()) rtIdx = i; VkPipelineColorBlendAttachmentState& blendState = mAttachmentBlendStates[i]; blendState.blendEnable = blendProps.getBlendEnabled(rtIdx); blendState.colorBlendOp = VulkanUtility::getBlendOp(blendProps.getBlendOperation(rtIdx)); blendState.srcColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getSrcBlend(rtIdx)); blendState.dstColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getDstBlend(rtIdx)); blendState.alphaBlendOp = VulkanUtility::getBlendOp(blendProps.getAlphaBlendOperation(rtIdx)); blendState.srcAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaSrcBlend(rtIdx)); blendState.dstAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaDstBlend(rtIdx)); blendState.colorWriteMask = blendProps.getRenderTargetWriteMask(rtIdx) & 0xF; } mColorBlendStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; mColorBlendStateInfo.pNext = nullptr; mColorBlendStateInfo.flags = 0; mColorBlendStateInfo.logicOpEnable = VK_FALSE; mColorBlendStateInfo.logicOp = VK_LOGIC_OP_NO_OP; mColorBlendStateInfo.attachmentCount = 0; // Assigned at runtime mColorBlendStateInfo.pAttachments = mAttachmentBlendStates; mColorBlendStateInfo.blendConstants[0] = 0.0f; mColorBlendStateInfo.blendConstants[1] = 0.0f; mColorBlendStateInfo.blendConstants[2] = 0.0f; mColorBlendStateInfo.blendConstants[3] = 0.0f; mDynamicStates[0] = VK_DYNAMIC_STATE_VIEWPORT; mDynamicStates[1] = VK_DYNAMIC_STATE_SCISSOR; mDynamicStates[2] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; UINT32 numDynamicStates = sizeof(mDynamicStates) / sizeof(mDynamicStates[0]); assert(numDynamicStates == 3); mDynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; mDynamicStateInfo.pNext = nullptr; mDynamicStateInfo.flags = 0; mDynamicStateInfo.dynamicStateCount = numDynamicStates; mDynamicStateInfo.pDynamicStates = mDynamicStates; mPipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; mPipelineInfo.pNext = nullptr; mPipelineInfo.flags = 0; mPipelineInfo.stageCount = numUsedStages; mPipelineInfo.pStages = mShaderStageInfos; mPipelineInfo.pVertexInputState = nullptr; // Assigned at runtime mPipelineInfo.pInputAssemblyState = &mInputAssemblyInfo; mPipelineInfo.pTessellationState = tesselationEnabled ? &mTesselationInfo : nullptr; mPipelineInfo.pViewportState = &mViewportInfo; mPipelineInfo.pRasterizationState = &mRasterizationInfo; mPipelineInfo.pMultisampleState = &mMultiSampleInfo; mPipelineInfo.pDepthStencilState = nullptr; // Assigned at runtime mPipelineInfo.pColorBlendState = nullptr; // Assigned at runtime mPipelineInfo.pDynamicState = &mDynamicStateInfo; mPipelineInfo.renderPass = VK_NULL_HANDLE; // Assigned at runtime mPipelineInfo.layout = VK_NULL_HANDLE; // Assigned at runtime mPipelineInfo.subpass = 0; mPipelineInfo.basePipelineHandle = VK_NULL_HANDLE; mPipelineInfo.basePipelineIndex = -1; mScissorEnabled = rstProps.getScissorEnable(); if(mData.vertexProgram != nullptr) mVertexDecl = mData.vertexProgram->getInputDeclaration(); VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance()); VulkanDevice* devices[BS_MAX_DEVICES]; VulkanUtility::getDevices(rapi, mDeviceMask, devices); for (UINT32 i = 0; i < BS_MAX_DEVICES; i++) { if (devices[i] == nullptr) continue; mPerDeviceData[i].device = devices[i]; VulkanDescriptorManager& descManager = mPerDeviceData[i].device->getDescriptorManager(); VulkanGpuPipelineParamInfo& vkParamInfo = static_cast<VulkanGpuPipelineParamInfo&>(*mParamInfo); UINT32 numLayouts = vkParamInfo.getNumSets(); VulkanDescriptorLayout** layouts = (VulkanDescriptorLayout**)bs_stack_alloc(sizeof(VulkanDescriptorLayout*) * numLayouts); for (UINT32 j = 0; j < numLayouts; j++) layouts[j] = vkParamInfo.getLayout(i, j); mPerDeviceData[i].pipelineLayout = descManager.getPipelineLayout(layouts, numLayouts); bs_stack_free(layouts); } BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState); }
void Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) { // First determine if a scissored clear is needed, this will always require drawing a quad. // // Otherwise, iterate over the color buffers which require clearing and determine if they can be // cleared with ID3D11DeviceContext::ClearRenderTargetView... This requires: // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer // render targets as expected but does not work the other way around) // 2) The format of the render target has no color channels that are currently masked out. // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. // // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView // by checking if the stencil write mask covers the entire stencil. // // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color // attribute. gl::Extents framebufferSize; if (frameBuffer->getFirstColorbuffer() != NULL) { gl::Renderbuffer *renderBuffer = frameBuffer->getFirstColorbuffer(); framebufferSize.width = renderBuffer->getWidth(); framebufferSize.height = renderBuffer->getHeight(); framebufferSize.depth = 1; } else if (frameBuffer->getDepthOrStencilbuffer() != NULL) { gl::Renderbuffer *renderBuffer = frameBuffer->getDepthOrStencilbuffer(); framebufferSize.width = renderBuffer->getWidth(); framebufferSize.height = renderBuffer->getHeight(); framebufferSize.depth = 1; } else { UNREACHABLE(); return; } if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.x + clearParams.scissor.width <= 0 || clearParams.scissor.y + clearParams.scissor.height <= 0)) { // Scissor is enabled and the scissor rectangle is outside the renderbuffer return; } bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); GLuint clientVersion = mRenderer->getCurrentClientVersion(); std::vector<RenderTarget11*> maskedClearRenderTargets; RenderTarget11* maskedClearDepthStencil = NULL; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { if (clearParams.clearColor[colorAttachment] && frameBuffer->isEnabledColorAttachment(colorAttachment)) { gl::Renderbuffer *renderbuffer = frameBuffer->getColorbuffer(colorAttachment); if (renderbuffer) { RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbuffer->getRenderTarget()); if (!renderTarget) { ERR("Render target pointer unexpectedly null."); return; } GLenum internalFormat = renderbuffer->getInternalFormat(); GLenum actualFormat = renderbuffer->getActualFormat(); GLenum componentType = gl::GetComponentType(internalFormat, clientVersion); if (clearParams.colorClearType == GL_FLOAT && !(componentType == GL_FLOAT || componentType == GL_UNSIGNED_NORMALIZED || componentType == GL_SIGNED_NORMALIZED)) { ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-" "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, internalFormat); } GLuint internalRedBits = gl::GetRedBits(internalFormat, clientVersion); GLuint internalGreenBits = gl::GetGreenBits(internalFormat, clientVersion); GLuint internalBlueBits = gl::GetBlueBits(internalFormat, clientVersion); GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat, clientVersion); if ((internalRedBits == 0 || !clearParams.colorMaskRed) && (internalGreenBits == 0 || !clearParams.colorMaskGreen) && (internalBlueBits == 0 || !clearParams.colorMaskBlue) && (internalAlphaBits == 0 || !clearParams.colorMaskAlpha)) { // Every channel either does not exist in the render target or is masked out continue; } else if (needScissoredClear || clearParams.colorClearType != GL_FLOAT || (internalRedBits > 0 && !clearParams.colorMaskRed) || (internalGreenBits > 0 && !clearParams.colorMaskGreen) || (internalBlueBits > 0 && !clearParams.colorMaskBlue) || (internalAlphaBits > 0 && !clearParams.colorMaskAlpha)) { // A scissored or masked clear is required maskedClearRenderTargets.push_back(renderTarget); } else { // ID3D11DeviceContext::ClearRenderTargetView is possible ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); if (!framebufferRTV) { ERR("Render target view pointer unexpectedly null."); return; } // Check if the actual format has a channel that the internal format does not and set them to the // default values GLuint actualRedBits = gl::GetRedBits(actualFormat, clientVersion); GLuint actualGreenBits = gl::GetGreenBits(actualFormat, clientVersion); GLuint actualBlueBits = gl::GetBlueBits(actualFormat, clientVersion); GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat, clientVersion); const float clearValues[4] = { ((internalRedBits == 0 && actualRedBits > 0) ? 0.0f : clearParams.colorFClearValue.red), ((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), ((internalBlueBits == 0 && actualBlueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), ((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), }; deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); } } } } if (clearParams.clearDepth || clearParams.clearStencil) { gl::Renderbuffer *renderbuffer = frameBuffer->getDepthOrStencilbuffer(); if (renderbuffer) { RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbuffer->getDepthStencil()); if (!renderTarget) { ERR("Depth stencil render target pointer unexpectedly null."); return; } GLenum actualFormat = renderbuffer->getActualFormat(); unsigned int stencilUnmasked = frameBuffer->hasStencil() ? (1 << gl::GetStencilBits(actualFormat, clientVersion)) - 1 : 0; bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; if (needScissoredClear || needMaskedStencilClear) { maskedClearDepthStencil = renderTarget; } else { ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); if (!framebufferDSV) { ERR("Depth stencil view pointer unexpectedly null."); return; } UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); } } } if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) { // To clear the render targets and depth stencil in one pass: // // Render a quad clipped to the scissor rectangle which draws the clear color and a blend // state that will perform the required color masking. // // The quad's depth is equal to the depth clear value with a depth stencil state that // will enable or disable depth test/writes if the depth buffer should be cleared or not. // // The rasterizer state's stencil is set to always pass or fail based on if the stencil // should be cleared or not with a stencil write mask of the stencil clear value. // // ====================================================================================== // // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- // buffer that is not normalized fixed point or floating point with floating point values // are undefined so we can just write floats to them and D3D11 will bit cast them to // integers. // // Also, we don't have to worry about attempting to clear a normalized fixed/floating point // buffer with integer values because there is no gl API call which would allow it, // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to // be a compatible clear type. // Bind all the render targets which need clearing ASSERT(maskedClearRenderTargets.size() <= mRenderer->getMaxRenderTargets()); std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size()); for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) { ID3D11RenderTargetView *renderTarget = maskedClearRenderTargets[i]->getRenderTargetView(); if (!renderTarget) { ERR("Render target pointer unexpectedly null."); return; } rtvs[i] = renderTarget; } ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL; ID3D11BlendState *blendState = getBlendState(clearParams, maskedClearRenderTargets); const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; const UINT sampleMask = 0xFFFFFFFF; ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); const UINT stencilClear = clearParams.stencilClearValue & 0xFF; // Set the vertices UINT vertexStride = 0; const UINT startIdx = 0; const ClearShader* shader = NULL; D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result); return; } const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL; switch (clearParams.colorClearType) { case GL_FLOAT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>); shader = &mFloatClearShader; break; case GL_UNSIGNED_INT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>); shader = &mUintClearShader; break; case GL_INT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>); shader = &mIntClearShader; break; default: UNREACHABLE(); break; } deviceContext->Unmap(mVertexBuffer, 0); // Set the viewport to be the same size as the framebuffer D3D11_VIEWPORT viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = framebufferSize.width; viewport.Height = framebufferSize.height; viewport.MinDepth = 0; viewport.MaxDepth = 1; deviceContext->RSSetViewports(1, &viewport); // Apply state deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); deviceContext->OMSetDepthStencilState(dsState, stencilClear); deviceContext->RSSetState(mRasterizerState); // Apply shaders deviceContext->IASetInputLayout(shader->inputLayout); deviceContext->VSSetShader(shader->vertexShader, NULL, 0); deviceContext->PSSetShader(shader->pixelShader, NULL, 0); deviceContext->GSSetShader(NULL, NULL, 0); // Apply vertex buffer deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); // Apply render targets deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv); // Draw the clear quad deviceContext->Draw(4, 0); // Clean up mRenderer->markAllStateDirty(); } }
gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData) { const auto &colorAttachments = fboData.mColorAttachments; const auto &drawBufferStates = fboData.mDrawBufferStates; const auto *depthAttachment = fboData.mDepthAttachment; const auto *stencilAttachment = fboData.mStencilAttachment; ASSERT(colorAttachments.size() == drawBufferStates.size()); // Iterate over the color buffers which require clearing and determine if they can be // cleared with ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView. // This requires: // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer // render targets as expected but does not work the other way around) // 2) The format of the render target has no color channels that are currently masked out. // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. // // If these conditions are met, and: // - No scissored clear is needed, then clear using ID3D11DeviceContext::ClearRenderTargetView. // - A scissored clear is needed then clear using ID3D11DeviceContext1::ClearView if available. // Otherwise draw a quad. // // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView // by checking if the stencil write mask covers the entire stencil. // // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color // attribute. gl::Extents framebufferSize; auto iter = std::find_if(colorAttachments.begin(), colorAttachments.end(), [](const gl::FramebufferAttachment *attachment) { return attachment != nullptr; }); if (iter != colorAttachments.end()) { framebufferSize.width = (*iter)->getWidth(); framebufferSize.height = (*iter)->getHeight(); framebufferSize.depth = 1; } else if (depthAttachment != nullptr) { framebufferSize.width = depthAttachment->getWidth(); framebufferSize.height = depthAttachment->getHeight(); framebufferSize.depth = 1; } else if (stencilAttachment != nullptr) { framebufferSize.width = stencilAttachment->getWidth(); framebufferSize.height = stencilAttachment->getHeight(); framebufferSize.depth = 1; } else { UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); } if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.x + clearParams.scissor.width <= 0 || clearParams.scissor.y + clearParams.scissor.height <= 0)) { // Scissor is enabled and the scissor rectangle is outside the renderbuffer return gl::Error(GL_NO_ERROR); } bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); std::vector<MaskedRenderTarget> maskedClearRenderTargets; RenderTarget11* maskedClearDepthStencil = NULL; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++) { if (clearParams.clearColor[colorAttachment] && colorAttachments[colorAttachment] != nullptr && drawBufferStates[colorAttachment] != GL_NONE) { const gl::FramebufferAttachment *attachment = colorAttachments[colorAttachment]; RenderTarget11 *renderTarget = NULL; gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); if (error.isError()) { return error; } const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat()); if (clearParams.colorClearType == GL_FLOAT && !(formatInfo.componentType == GL_FLOAT || formatInfo.componentType == GL_UNSIGNED_NORMALIZED || formatInfo.componentType == GL_SIGNED_NORMALIZED)) { ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-" "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, attachment->getInternalFormat()); } if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) && (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) && (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) && (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha)) { // Every channel either does not exist in the render target or is masked out continue; } else if ((!mSupportsClearView && needScissoredClear) || clearParams.colorClearType != GL_FLOAT || (formatInfo.redBits > 0 && !clearParams.colorMaskRed) || (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) { // A masked clear is required, or a scissored clear is required and ID3D11DeviceContext1::ClearView is unavailable MaskedRenderTarget maskAndRt; bool clearColor = clearParams.clearColor[colorAttachment]; maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed); maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen); maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue); maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha); maskAndRt.renderTarget = renderTarget; maskedClearRenderTargets.push_back(maskAndRt); } else { // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is possible ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); if (!framebufferRTV) { return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); } const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); // Check if the actual format has a channel that the internal format does not and set them to the // default values const float clearValues[4] = { ((formatInfo.redBits == 0 && dxgiFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), ((formatInfo.greenBits == 0 && dxgiFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), ((formatInfo.blueBits == 0 && dxgiFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), ((formatInfo.alphaBits == 0 && dxgiFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), }; if (needScissoredClear) { // We shouldn't reach here if deviceContext1 is unavailable. ASSERT(deviceContext1); D3D11_RECT rect; rect.left = clearParams.scissor.x; rect.right = clearParams.scissor.x + clearParams.scissor.width; rect.top = clearParams.scissor.y; rect.bottom = clearParams.scissor.y + clearParams.scissor.height; deviceContext1->ClearView(framebufferRTV, clearValues, &rect, 1); } else { deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); } } } } if (clearParams.clearDepth || clearParams.clearStencil) { const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment; ASSERT(attachment != nullptr); RenderTarget11 *renderTarget = NULL; gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); if (error.isError()) { return error; } const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); unsigned int stencilUnmasked = (stencilAttachment != nullptr) ? (1 << dxgiFormatInfo.stencilBits) - 1 : 0; bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; if (needScissoredClear || needMaskedStencilClear) { maskedClearDepthStencil = renderTarget; } else { ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); if (!framebufferDSV) { return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); } UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); } } if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) { // To clear the render targets and depth stencil in one pass: // // Render a quad clipped to the scissor rectangle which draws the clear color and a blend // state that will perform the required color masking. // // The quad's depth is equal to the depth clear value with a depth stencil state that // will enable or disable depth test/writes if the depth buffer should be cleared or not. // // The rasterizer state's stencil is set to always pass or fail based on if the stencil // should be cleared or not with a stencil write mask of the stencil clear value. // // ====================================================================================== // // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- // buffer that is not normalized fixed point or floating point with floating point values // are undefined so we can just write floats to them and D3D11 will bit cast them to // integers. // // Also, we don't have to worry about attempting to clear a normalized fixed/floating point // buffer with integer values because there is no gl API call which would allow it, // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to // be a compatible clear type. // Bind all the render targets which need clearing ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers); std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size()); for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) { RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget; ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView(); if (!rtv) { return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); } rtvs[i] = rtv; } ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL; ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; const UINT sampleMask = 0xFFFFFFFF; ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); const UINT stencilClear = clearParams.stencilClearValue & 0xFF; // Set the vertices UINT vertexStride = 0; const UINT startIdx = 0; const ClearShader* shader = NULL; D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result); } const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL; switch (clearParams.colorClearType) { case GL_FLOAT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>); shader = &mFloatClearShader; break; case GL_UNSIGNED_INT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>); shader = &mUintClearShader; break; case GL_INT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>); shader = &mIntClearShader; break; default: UNREACHABLE(); break; } deviceContext->Unmap(mVertexBuffer, 0); // Set the viewport to be the same size as the framebuffer D3D11_VIEWPORT viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = framebufferSize.width; viewport.Height = framebufferSize.height; viewport.MinDepth = 0; viewport.MaxDepth = 1; deviceContext->RSSetViewports(1, &viewport); // Apply state deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); deviceContext->OMSetDepthStencilState(dsState, stencilClear); deviceContext->RSSetState(mRasterizerState); // Apply shaders deviceContext->IASetInputLayout(shader->inputLayout); deviceContext->VSSetShader(shader->vertexShader, NULL, 0); deviceContext->PSSetShader(shader->pixelShader, NULL, 0); deviceContext->GSSetShader(NULL, NULL, 0); // Apply vertex buffer deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); // Apply render targets deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv); // Draw the clear quad deviceContext->Draw(4, 0); // Clean up mRenderer->markAllStateDirty(); } return gl::Error(GL_NO_ERROR); }