Пример #1
0
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);
		}
	}
}
Пример #2
0
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);
	}
Пример #4
0
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();
    }
}
Пример #5
0
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);
}