2016-12-29 09:31:51 -07:00
|
|
|
// Copyright 2016 Dolphin Emulator Project
|
2021-07-04 19:22:19 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2016-12-29 09:31:51 -07:00
|
|
|
|
|
|
|
#include "VideoCommon/RenderState.h"
|
2021-08-08 12:05:32 -06:00
|
|
|
|
2017-09-09 02:30:15 -06:00
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
2021-08-08 12:05:32 -06:00
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
#include "VideoCommon/TextureConfig.h"
|
2016-12-29 09:31:51 -07:00
|
|
|
|
2017-04-30 02:07:57 -06:00
|
|
|
void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_type)
|
|
|
|
{
|
|
|
|
cullmode = bp.genMode.cullmode;
|
|
|
|
primitive = primitive_type;
|
|
|
|
|
|
|
|
// Back-face culling should be disabled for points/lines.
|
|
|
|
if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip)
|
2021-02-10 19:11:31 -07:00
|
|
|
cullmode = CullMode::None;
|
2017-04-30 02:07:57 -06:00
|
|
|
}
|
|
|
|
|
2017-04-29 23:54:45 -06:00
|
|
|
void DepthState::Generate(const BPMemory& bp)
|
|
|
|
{
|
|
|
|
testenable = bp.zmode.testenable.Value();
|
|
|
|
updateenable = bp.zmode.updateenable.Value();
|
|
|
|
func = bp.zmode.func.Value();
|
|
|
|
}
|
|
|
|
|
2016-12-29 09:31:51 -07:00
|
|
|
// If the framebuffer format has no alpha channel, it is assumed to
|
|
|
|
// ONE on blending. As the backends may emulate this framebuffer
|
|
|
|
// configuration with an alpha channel, we just drop all references
|
|
|
|
// to the destination alpha channel.
|
2021-02-10 19:11:31 -07:00
|
|
|
static SrcBlendFactor RemoveDstAlphaUsage(SrcBlendFactor factor)
|
2016-12-29 09:31:51 -07:00
|
|
|
{
|
|
|
|
switch (factor)
|
|
|
|
{
|
2021-02-10 19:11:31 -07:00
|
|
|
case SrcBlendFactor::DstAlpha:
|
|
|
|
return SrcBlendFactor::One;
|
|
|
|
case SrcBlendFactor::InvDstAlpha:
|
|
|
|
return SrcBlendFactor::Zero;
|
|
|
|
default:
|
|
|
|
return factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static DstBlendFactor RemoveDstAlphaUsage(DstBlendFactor factor)
|
|
|
|
{
|
|
|
|
switch (factor)
|
|
|
|
{
|
|
|
|
case DstBlendFactor::DstAlpha:
|
|
|
|
return DstBlendFactor::One;
|
|
|
|
case DstBlendFactor::InvDstAlpha:
|
|
|
|
return DstBlendFactor::Zero;
|
2016-12-29 09:31:51 -07:00
|
|
|
default:
|
|
|
|
return factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We separate the blending parameter for rgb and alpha. For blending
|
|
|
|
// the alpha component, CLR and ALPHA are indentical. So just always
|
|
|
|
// use ALPHA as this makes it easier for the backends to use the second
|
|
|
|
// alpha value of dual source blending.
|
2021-02-10 19:11:31 -07:00
|
|
|
static DstBlendFactor RemoveSrcColorUsage(DstBlendFactor factor)
|
2016-12-29 09:31:51 -07:00
|
|
|
{
|
|
|
|
switch (factor)
|
|
|
|
{
|
2021-02-10 19:11:31 -07:00
|
|
|
case DstBlendFactor::SrcClr:
|
|
|
|
return DstBlendFactor::SrcAlpha;
|
|
|
|
case DstBlendFactor::InvSrcClr:
|
|
|
|
return DstBlendFactor::InvSrcAlpha;
|
2016-12-29 09:31:51 -07:00
|
|
|
default:
|
|
|
|
return factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same as RemoveSrcColorUsage, but because of the overlapping enum,
|
|
|
|
// this must be written as another function.
|
2021-02-10 19:11:31 -07:00
|
|
|
static SrcBlendFactor RemoveDstColorUsage(SrcBlendFactor factor)
|
2016-12-29 09:31:51 -07:00
|
|
|
{
|
|
|
|
switch (factor)
|
|
|
|
{
|
2021-02-10 19:11:31 -07:00
|
|
|
case SrcBlendFactor::DstClr:
|
|
|
|
return SrcBlendFactor::DstAlpha;
|
|
|
|
case SrcBlendFactor::InvDstClr:
|
|
|
|
return SrcBlendFactor::InvDstAlpha;
|
2016-12-29 09:31:51 -07:00
|
|
|
default:
|
|
|
|
return factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BlendingState::Generate(const BPMemory& bp)
|
|
|
|
{
|
|
|
|
// Start with everything disabled.
|
|
|
|
hex = 0;
|
|
|
|
|
2021-02-10 19:11:31 -07:00
|
|
|
bool target_has_alpha = bp.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
|
|
|
|
bool alpha_test_may_succeed = bp.alpha_test.TestResult() != AlphaTestResult::Fail;
|
2016-12-29 09:31:51 -07:00
|
|
|
|
2021-02-10 19:11:31 -07:00
|
|
|
colorupdate = bp.blendmode.colorupdate && alpha_test_may_succeed;
|
|
|
|
alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_succeed;
|
2016-12-29 09:31:51 -07:00
|
|
|
dstalpha = bp.dstalpha.enable && alphaupdate;
|
2017-04-17 07:11:58 -06:00
|
|
|
usedualsrc = true;
|
2016-12-29 09:31:51 -07:00
|
|
|
|
|
|
|
// The subtract bit has the highest priority
|
|
|
|
if (bp.blendmode.subtract)
|
|
|
|
{
|
|
|
|
blendenable = true;
|
|
|
|
subtractAlpha = subtract = true;
|
2021-02-10 19:11:31 -07:00
|
|
|
srcfactoralpha = srcfactor = SrcBlendFactor::One;
|
|
|
|
dstfactoralpha = dstfactor = DstBlendFactor::One;
|
2016-12-29 09:31:51 -07:00
|
|
|
|
|
|
|
if (dstalpha)
|
|
|
|
{
|
|
|
|
subtractAlpha = false;
|
2021-02-10 19:11:31 -07:00
|
|
|
srcfactoralpha = SrcBlendFactor::One;
|
|
|
|
dstfactoralpha = DstBlendFactor::Zero;
|
2016-12-29 09:31:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The blendenable bit has the middle priority
|
|
|
|
else if (bp.blendmode.blendenable)
|
|
|
|
{
|
|
|
|
blendenable = true;
|
|
|
|
srcfactor = bp.blendmode.srcfactor;
|
|
|
|
dstfactor = bp.blendmode.dstfactor;
|
|
|
|
if (!target_has_alpha)
|
|
|
|
{
|
|
|
|
// uses ONE instead of DSTALPHA
|
|
|
|
srcfactor = RemoveDstAlphaUsage(srcfactor);
|
|
|
|
dstfactor = RemoveDstAlphaUsage(dstfactor);
|
|
|
|
}
|
2021-02-10 19:11:31 -07:00
|
|
|
// replaces SrcClr with SrcAlpha and DstClr with DstAlpha, it is important to
|
2017-08-21 08:08:32 -06:00
|
|
|
// use the dst function for the src factor and vice versa
|
|
|
|
srcfactoralpha = RemoveDstColorUsage(srcfactor);
|
|
|
|
dstfactoralpha = RemoveSrcColorUsage(dstfactor);
|
2016-12-29 09:31:51 -07:00
|
|
|
|
|
|
|
if (dstalpha)
|
|
|
|
{
|
2021-02-10 19:11:31 -07:00
|
|
|
srcfactoralpha = SrcBlendFactor::One;
|
|
|
|
dstfactoralpha = DstBlendFactor::Zero;
|
2016-12-29 09:31:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The logicop bit has the lowest priority
|
|
|
|
else if (bp.blendmode.logicopenable)
|
|
|
|
{
|
2021-02-10 19:11:31 -07:00
|
|
|
if (bp.blendmode.logicmode == LogicOp::NoOp)
|
2016-12-29 09:31:51 -07:00
|
|
|
{
|
2016-12-29 10:15:41 -07:00
|
|
|
// Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
|
|
|
|
colorupdate = false;
|
|
|
|
alphaupdate = alphaupdate && dstalpha;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
logicopenable = true;
|
|
|
|
logicmode = bp.blendmode.logicmode;
|
|
|
|
|
|
|
|
if (dstalpha)
|
|
|
|
{
|
|
|
|
// TODO: Not supported by backends.
|
|
|
|
}
|
2016-12-29 09:31:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-08 08:10:40 -06:00
|
|
|
|
2019-08-02 03:20:36 -06:00
|
|
|
void BlendingState::ApproximateLogicOpWithBlending()
|
|
|
|
{
|
|
|
|
struct LogicOpApproximation
|
|
|
|
{
|
|
|
|
bool subtract;
|
2021-02-10 19:11:31 -07:00
|
|
|
SrcBlendFactor srcfactor;
|
|
|
|
DstBlendFactor dstfactor;
|
2019-08-02 03:20:36 -06:00
|
|
|
};
|
2021-02-10 19:11:31 -07:00
|
|
|
// TODO: This previously had a warning about SRC and DST being aliased and not to mix them,
|
|
|
|
// but INVSRCCLR and INVDSTCLR were also aliased and were mixed.
|
|
|
|
// Thus, NOR, EQUIV, INVERT, COPY_INVERTED, and OR_INVERTED duplicate(d) other values.
|
2019-08-02 03:20:36 -06:00
|
|
|
static constexpr std::array<LogicOpApproximation, 16> approximations = {{
|
2021-02-10 19:11:31 -07:00
|
|
|
{false, SrcBlendFactor::Zero, DstBlendFactor::Zero}, // CLEAR
|
|
|
|
{false, SrcBlendFactor::DstClr, DstBlendFactor::Zero}, // AND
|
|
|
|
{true, SrcBlendFactor::One, DstBlendFactor::InvSrcClr}, // AND_REVERSE
|
|
|
|
{false, SrcBlendFactor::One, DstBlendFactor::Zero}, // COPY
|
|
|
|
{true, SrcBlendFactor::DstClr, DstBlendFactor::One}, // AND_INVERTED
|
|
|
|
{false, SrcBlendFactor::Zero, DstBlendFactor::One}, // NOOP
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // XOR
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NOR
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::Zero}, // EQUIV
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // INVERT
|
|
|
|
{false, SrcBlendFactor::One, DstBlendFactor::InvDstAlpha}, // OR_REVERSE
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // COPY_INVERTED
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR_INVERTED
|
|
|
|
{false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NAND
|
|
|
|
{false, SrcBlendFactor::One, DstBlendFactor::One}, // SET
|
2019-08-02 03:20:36 -06:00
|
|
|
}};
|
|
|
|
|
|
|
|
logicopenable = false;
|
|
|
|
blendenable = true;
|
2021-02-10 19:11:31 -07:00
|
|
|
subtract = approximations[u32(logicmode.Value())].subtract;
|
|
|
|
srcfactor = approximations[u32(logicmode.Value())].srcfactor;
|
2022-02-07 13:46:20 -07:00
|
|
|
srcfactoralpha = approximations[u32(logicmode.Value())].srcfactor;
|
2021-02-10 19:11:31 -07:00
|
|
|
dstfactor = approximations[u32(logicmode.Value())].dstfactor;
|
2022-02-07 13:46:20 -07:00
|
|
|
dstfactoralpha = approximations[u32(logicmode.Value())].dstfactor;
|
2019-08-02 03:20:36 -06:00
|
|
|
}
|
|
|
|
|
2017-09-09 02:30:15 -06:00
|
|
|
void SamplerState::Generate(const BPMemory& bp, u32 index)
|
|
|
|
{
|
2021-10-09 13:16:15 -06:00
|
|
|
auto tex = bp.tex.GetUnit(index);
|
2021-08-08 22:11:50 -06:00
|
|
|
const TexMode0& bp_tm0 = tex.texMode0;
|
|
|
|
const TexMode1& bp_tm1 = tex.texMode1;
|
2017-09-09 02:30:15 -06:00
|
|
|
|
|
|
|
// GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their
|
|
|
|
// sampler states. Therefore, we set the min/max LOD to zero if this option is used.
|
2021-08-08 22:11:50 -06:00
|
|
|
tm0.min_filter = bp_tm0.min_filter;
|
|
|
|
tm0.mipmap_filter =
|
|
|
|
bp_tm0.mipmap_filter == MipMode::Linear ? FilterMode::Linear : FilterMode::Near;
|
|
|
|
tm0.mag_filter = bp_tm0.mag_filter;
|
2017-09-09 02:30:15 -06:00
|
|
|
|
|
|
|
// If mipmaps are disabled, clamp min/max lod
|
2021-08-08 22:11:50 -06:00
|
|
|
if (bp_tm0.mipmap_filter == MipMode::None)
|
|
|
|
{
|
|
|
|
tm1.max_lod = 0;
|
|
|
|
tm1.min_lod = 0;
|
|
|
|
tm0.lod_bias = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// NOTE: When comparing, max is checked first, then min; if max is less than min, max wins
|
|
|
|
tm1.max_lod = bp_tm1.max_lod.Value();
|
|
|
|
tm1.min_lod = std::min(tm1.max_lod.Value(), bp_tm1.min_lod.Value());
|
|
|
|
tm0.lod_bias = bp_tm0.lod_bias * (256 / 32);
|
|
|
|
}
|
2017-09-09 02:30:15 -06:00
|
|
|
|
2021-08-08 22:11:50 -06:00
|
|
|
// Wrap modes
|
2021-07-20 13:53:32 -06:00
|
|
|
// Hardware testing indicates that wrap_mode set to 3 behaves the same as clamp.
|
2021-08-08 22:11:50 -06:00
|
|
|
auto filter_invalid_wrap = [](WrapMode mode) {
|
|
|
|
return (mode <= WrapMode::Mirror) ? mode : WrapMode::Clamp;
|
|
|
|
};
|
|
|
|
tm0.wrap_u = filter_invalid_wrap(bp_tm0.wrap_s);
|
|
|
|
tm0.wrap_v = filter_invalid_wrap(bp_tm0.wrap_t);
|
|
|
|
|
|
|
|
tm0.diag_lod = bp_tm0.diag_lod;
|
|
|
|
tm0.anisotropic_filtering = false; // TODO: Respect BP anisotropic filtering mode
|
|
|
|
tm0.lod_clamp = bp_tm0.lod_clamp; // TODO: What does this do?
|
2017-09-09 02:30:15 -06:00
|
|
|
}
|
|
|
|
|
2017-09-08 08:10:40 -06:00
|
|
|
namespace RenderState
|
|
|
|
{
|
2019-01-19 06:54:35 -07:00
|
|
|
RasterizationState GetInvalidRasterizationState()
|
|
|
|
{
|
|
|
|
RasterizationState state;
|
|
|
|
state.hex = UINT32_C(0xFFFFFFFF);
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
RasterizationState GetNoCullRasterizationState(PrimitiveType primitive)
|
2017-09-08 08:10:40 -06:00
|
|
|
{
|
|
|
|
RasterizationState state = {};
|
2021-02-10 19:11:31 -07:00
|
|
|
state.cullmode = CullMode::None;
|
2019-02-14 18:59:50 -07:00
|
|
|
state.primitive = primitive;
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
RasterizationState GetCullBackFaceRasterizationState(PrimitiveType primitive)
|
|
|
|
{
|
|
|
|
RasterizationState state = {};
|
2021-02-10 19:11:31 -07:00
|
|
|
state.cullmode = CullMode::Back;
|
2019-02-14 18:59:50 -07:00
|
|
|
state.primitive = primitive;
|
2017-09-08 08:10:40 -06:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2019-01-19 06:54:35 -07:00
|
|
|
DepthState GetInvalidDepthState()
|
|
|
|
{
|
|
|
|
DepthState state;
|
|
|
|
state.hex = UINT32_C(0xFFFFFFFF);
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
DepthState GetNoDepthTestingDepthState()
|
2017-09-08 08:10:40 -06:00
|
|
|
{
|
|
|
|
DepthState state = {};
|
|
|
|
state.testenable = false;
|
|
|
|
state.updateenable = false;
|
2021-02-10 19:11:31 -07:00
|
|
|
state.func = CompareMode::Always;
|
2017-09-08 08:10:40 -06:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
DepthState GetAlwaysWriteDepthState()
|
|
|
|
{
|
|
|
|
DepthState state = {};
|
|
|
|
state.testenable = true;
|
|
|
|
state.updateenable = true;
|
2021-02-10 19:11:31 -07:00
|
|
|
state.func = CompareMode::Always;
|
2019-02-14 18:59:50 -07:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2019-01-19 06:54:35 -07:00
|
|
|
BlendingState GetInvalidBlendingState()
|
|
|
|
{
|
|
|
|
BlendingState state;
|
|
|
|
state.hex = UINT32_C(0xFFFFFFFF);
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2017-09-08 08:10:40 -06:00
|
|
|
BlendingState GetNoBlendingBlendState()
|
|
|
|
{
|
|
|
|
BlendingState state = {};
|
|
|
|
state.usedualsrc = false;
|
|
|
|
state.blendenable = false;
|
2021-02-10 19:11:31 -07:00
|
|
|
state.srcfactor = SrcBlendFactor::One;
|
|
|
|
state.srcfactoralpha = SrcBlendFactor::One;
|
|
|
|
state.dstfactor = DstBlendFactor::Zero;
|
|
|
|
state.dstfactoralpha = DstBlendFactor::Zero;
|
2017-09-08 08:10:40 -06:00
|
|
|
state.logicopenable = false;
|
|
|
|
state.colorupdate = true;
|
|
|
|
state.alphaupdate = true;
|
|
|
|
return state;
|
|
|
|
}
|
2017-09-09 02:30:15 -06:00
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
BlendingState GetNoColorWriteBlendState()
|
|
|
|
{
|
|
|
|
BlendingState state = {};
|
|
|
|
state.usedualsrc = false;
|
|
|
|
state.blendenable = false;
|
2021-02-10 19:11:31 -07:00
|
|
|
state.srcfactor = SrcBlendFactor::One;
|
|
|
|
state.srcfactoralpha = SrcBlendFactor::One;
|
|
|
|
state.dstfactor = DstBlendFactor::Zero;
|
|
|
|
state.dstfactoralpha = DstBlendFactor::Zero;
|
2019-02-14 18:59:50 -07:00
|
|
|
state.logicopenable = false;
|
|
|
|
state.colorupdate = false;
|
|
|
|
state.alphaupdate = false;
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2019-01-19 06:54:35 -07:00
|
|
|
SamplerState GetInvalidSamplerState()
|
|
|
|
{
|
|
|
|
SamplerState state;
|
2021-08-08 22:11:50 -06:00
|
|
|
state.tm0.hex = 0xFFFFFFFF;
|
|
|
|
state.tm1.hex = 0xFFFFFFFF;
|
2019-01-19 06:54:35 -07:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2017-09-09 02:30:15 -06:00
|
|
|
SamplerState GetPointSamplerState()
|
|
|
|
{
|
|
|
|
SamplerState state = {};
|
2021-08-08 22:11:50 -06:00
|
|
|
state.tm0.min_filter = FilterMode::Near;
|
|
|
|
state.tm0.mag_filter = FilterMode::Near;
|
|
|
|
state.tm0.mipmap_filter = FilterMode::Near;
|
|
|
|
state.tm0.wrap_u = WrapMode::Clamp;
|
|
|
|
state.tm0.wrap_v = WrapMode::Clamp;
|
|
|
|
state.tm1.min_lod = 0;
|
|
|
|
state.tm1.max_lod = 255;
|
|
|
|
state.tm0.lod_bias = 0;
|
|
|
|
state.tm0.anisotropic_filtering = false;
|
|
|
|
state.tm0.diag_lod = LODType::Edge;
|
|
|
|
state.tm0.lod_clamp = false;
|
2017-09-09 02:30:15 -06:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
SamplerState GetLinearSamplerState()
|
|
|
|
{
|
|
|
|
SamplerState state = {};
|
2021-08-08 22:11:50 -06:00
|
|
|
state.tm0.min_filter = FilterMode::Linear;
|
|
|
|
state.tm0.mag_filter = FilterMode::Linear;
|
|
|
|
state.tm0.mipmap_filter = FilterMode::Linear;
|
|
|
|
state.tm0.wrap_u = WrapMode::Clamp;
|
|
|
|
state.tm0.wrap_v = WrapMode::Clamp;
|
|
|
|
state.tm1.min_lod = 0;
|
|
|
|
state.tm1.max_lod = 255;
|
|
|
|
state.tm0.lod_bias = 0;
|
|
|
|
state.tm0.anisotropic_filtering = false;
|
|
|
|
state.tm0.diag_lod = LODType::Edge;
|
|
|
|
state.tm0.lod_clamp = false;
|
2017-09-09 02:30:15 -06:00
|
|
|
return state;
|
|
|
|
}
|
2019-02-14 18:59:50 -07:00
|
|
|
|
|
|
|
FramebufferState GetColorFramebufferState(AbstractTextureFormat format)
|
|
|
|
{
|
|
|
|
FramebufferState state = {};
|
|
|
|
state.color_texture_format = format;
|
|
|
|
state.depth_texture_format = AbstractTextureFormat::Undefined;
|
|
|
|
state.per_sample_shading = false;
|
|
|
|
state.samples = 1;
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
FramebufferState GetRGBA8FramebufferState()
|
|
|
|
{
|
|
|
|
return GetColorFramebufferState(AbstractTextureFormat::RGBA8);
|
2017-09-08 08:10:40 -06:00
|
|
|
}
|
2019-02-14 18:59:50 -07:00
|
|
|
|
|
|
|
} // namespace RenderState
|