Remove the use of bitfields for Gpu::Color16. These were a portability hazard, since the bitfield layout is compiler dependent.

This commit is contained in:
Darragh Coy 2022-01-27 15:19:48 -08:00
parent 52b3028fd6
commit 74b31bdbaf
4 changed files with 69 additions and 46 deletions

View File

@ -1,5 +1,4 @@
- Implement integer scaling.
- Fix reliance on bitfields for 16-bit pixels via 'Color16' (bitfield order implementation dependant).
- Fix reliance on bitfields for network code via 'TickInputs' (bitfield order implementation dependant).
- Fix reliance on bitfields for 'spu::AdsrEnvelope' (bitfield order implementation dependant).
- Linux support.

View File

@ -232,9 +232,9 @@ void VideoBackend_SDL::copyPsxToSdlFramebufferTexture() noexcept {
// Note: don't bother doing multiple pixels at a time - compiler is smart and already optimizes this to use SIMD
for (uint32_t x = xStart; x < xEnd; ++x, ++pDstPixel) {
const Gpu::Color16 srcPixel = rowPixels[x];
const uint32_t r = (uint32_t) srcPixel.comp.r << 3;
const uint32_t g = (uint32_t) srcPixel.comp.g << 3;
const uint32_t b = (uint32_t) srcPixel.comp.b << 3;
const uint32_t r = (uint32_t) srcPixel.getR() << 3;
const uint32_t g = (uint32_t) srcPixel.getG() << 3;
const uint32_t b = (uint32_t) srcPixel.getB() << 3;
*pDstPixel = (0xFF000000 | (b << 16) | (g << 8 ) | (r << 0));
}

View File

@ -261,11 +261,11 @@ Color16 color24FTo16(const Color24F colorIn) noexcept {
constexpr uint32_t COLOR_NORMALIZE = (bIsTextured) ? 128 : 255;
constexpr uint32_t ROUND_UP = (bIsTextured) ? 0 : 128;
Color16 colorOut;
colorOut.comp.r = (uint16_t) std::min(((uint32_t) colorIn.comp.r * 31u + ROUND_UP) / COLOR_NORMALIZE, 31u);
colorOut.comp.g = (uint16_t) std::min(((uint32_t) colorIn.comp.g * 31u + ROUND_UP) / COLOR_NORMALIZE, 31u);
colorOut.comp.b = (uint16_t) std::min(((uint32_t) colorIn.comp.b * 31u + ROUND_UP) / COLOR_NORMALIZE, 31u);
return colorOut;
return Color16::make(
(uint16_t) std::min(((uint32_t) colorIn.comp.r * 31u + ROUND_UP) / COLOR_NORMALIZE, 31u),
(uint16_t) std::min(((uint32_t) colorIn.comp.g * 31u + ROUND_UP) / COLOR_NORMALIZE, 31u),
(uint16_t) std::min(((uint32_t) colorIn.comp.b * 31u + ROUND_UP) / COLOR_NORMALIZE, 31u)
);
}
// Instantiate the variants of this function
@ -278,12 +278,12 @@ template Color16 color24FTo16<DrawMode::TexturedBlended>(const Color24F colorIn)
// Modulate a 16-bit color by a 24-bit one where the components are in 1.7 fixed point format
//------------------------------------------------------------------------------------------------------------------------------------------
Color16 colorMul(const Color16 color1, const Color24F color2) noexcept {
Color16 out;
out.comp.r = (uint16_t) std::min((color1.comp.r * color2.comp.r) >> 7, 31);
out.comp.g = (uint16_t) std::min((color1.comp.g * color2.comp.g) >> 7, 31);
out.comp.b = (uint16_t) std::min((color1.comp.b * color2.comp.b) >> 7, 31);
out.comp.t = color1.comp.t;
return out;
return Color16::make(
(uint16_t) std::min((color1.getR() * color2.comp.r) >> 7, 31),
(uint16_t) std::min((color1.getG() * color2.comp.g) >> 7, 31),
(uint16_t) std::min((color1.getB() * color2.comp.b) >> 7, 31),
color1.getT()
);
}
//------------------------------------------------------------------------------------------------------------------------------------------
@ -294,27 +294,35 @@ Color16 colorBlend(const Color16 bg, const Color16 fg, const BlendMode mode) noe
switch (mode) {
case BlendMode::Alpha50:
result.comp.r = (uint16_t)((bg.comp.r + fg.comp.r) >> 1);
result.comp.g = (uint16_t)((bg.comp.g + fg.comp.g) >> 1);
result.comp.b = (uint16_t)((bg.comp.b + fg.comp.b) >> 1);
result.setRGB(
(uint16_t)((bg.getR() + fg.getR()) >> 1),
(uint16_t)((bg.getG() + fg.getG()) >> 1),
(uint16_t)((bg.getB() + fg.getB()) >> 1)
);
break;
case BlendMode::Add:
result.comp.r = (uint16_t) std::min(bg.comp.r + fg.comp.r, 31);
result.comp.g = (uint16_t) std::min(bg.comp.g + fg.comp.g, 31);
result.comp.b = (uint16_t) std::min(bg.comp.b + fg.comp.b, 31);
result.setRGB(
(uint16_t) std::min(bg.getR() + fg.getR(), 31),
(uint16_t) std::min(bg.getG() + fg.getG(), 31),
(uint16_t) std::min(bg.getB() + fg.getB(), 31)
);
break;
case BlendMode::Subtract:
result.comp.r = (uint16_t) std::max((int32_t) bg.comp.r - (int32_t) fg.comp.r, 0);
result.comp.g = (uint16_t) std::max((int32_t) bg.comp.g - (int32_t) fg.comp.g, 0);
result.comp.b = (uint16_t) std::max((int32_t) bg.comp.b - (int32_t) fg.comp.b, 0);
result.setRGB(
(uint16_t) std::max((int32_t) bg.getR() - (int32_t) fg.getR(), 0),
(uint16_t) std::max((int32_t) bg.getG() - (int32_t) fg.getG(), 0),
(uint16_t) std::max((int32_t) bg.getB() - (int32_t) fg.getB(), 0)
);
break;
case BlendMode::Add25:
result.comp.r = (uint16_t) std::min(bg.comp.r + (fg.comp.r >> 2), 31);
result.comp.g = (uint16_t) std::min(bg.comp.g + (fg.comp.g >> 2), 31);
result.comp.b = (uint16_t) std::min(bg.comp.b + (fg.comp.b >> 2), 31);
result.setRGB(
(uint16_t) std::min(bg.getR() + (fg.getR() >> 2), 31),
(uint16_t) std::min(bg.getG() + (fg.getG() >> 2), 31),
(uint16_t) std::min(bg.getB() + (fg.getB() >> 2), 31)
);
break;
}
@ -835,10 +843,11 @@ static void draw(Core& core, const DrawTriangleGouraud& triangle) noexcept {
}
else {
// Not doing texture mapping: foreground color is just the interpolated color
fgColor.comp.r = std::min<uint16_t>(((uint16_t) gColorR + 4) >> 3, 31u);
fgColor.comp.g = std::min<uint16_t>(((uint16_t) gColorG + 4) >> 3, 31u);
fgColor.comp.b = std::min<uint16_t>(((uint16_t) gColorB + 4) >> 3, 31u);
fgColor.comp.t = 0;
fgColor = Color16::make(
std::min<uint16_t>(((uint16_t) gColorR + 4) >> 3, 31u),
std::min<uint16_t>(((uint16_t) gColorG + 4) >> 3, 31u),
std::min<uint16_t>(((uint16_t) gColorB + 4) >> 3, 31u)
);
}
// Do blending with the background if that is enabled
@ -1242,10 +1251,11 @@ void draw(Core& core, const DrawWallColGouraud& col) noexcept {
fgColor = colorMul(fgColor, colColor);
} else {
// Not doing texture mapping: foreground color is just the interpolated color
fgColor.comp.r = std::min<uint16_t>(((uint16_t) gColorR + 4) >> 3, 31u);
fgColor.comp.g = std::min<uint16_t>(((uint16_t) gColorG + 4) >> 3, 31u);
fgColor.comp.b = std::min<uint16_t>(((uint16_t) gColorB + 4) >> 3, 31u);
fgColor.comp.t = 0;
fgColor = Color16::make(
std::min<uint16_t>(((uint16_t) gColorR + 4) >> 3, 31u),
std::min<uint16_t>(((uint16_t) gColorG + 4) >> 3, 31u),
std::min<uint16_t>(((uint16_t) gColorB + 4) >> 3, 31u)
);
}
// Do blending with the background if that is enabled

View File

@ -67,24 +67,38 @@ union Color24F {
};
//----------------------------------------------------------------------------------------------------------------------
// Represents a 15-bit BGR555 color used by the GPU plus 1 bit that says whether blending is enabled for the pixel.
// Represents a 15-bit TBGR1555 color used by the GPU.
// This is used as a dest/output format for the framebuffer and also as an input format for 16-bit textures & CLUTs.
// Note: the top bit (T) is the PlayStation 'semi-transparency' bit.
//----------------------------------------------------------------------------------------------------------------------
union Color16 {
// The individual components of the color
struct {
uint16_t r : 5;
uint16_t g : 5;
uint16_t b : 5;
uint16_t t : 1; // High bit: blending/semi-transparency flag. If set then blend the pixel, if drawing a blended primitive.
} comp;
// The full 16-bits of the color
struct Color16 {
uint16_t bits;
inline constexpr uint16_t getR() const noexcept { return bits & 0x1F; }
inline constexpr uint16_t getG() const noexcept { return (bits >> 5) & 0x1F; }
inline constexpr uint16_t getB() const noexcept { return (bits >> 10) & 0x1F; }
inline constexpr uint16_t getT() const noexcept { return bits >> 15; }
inline constexpr Color16() noexcept : bits(0) {}
inline constexpr Color16(const uint16_t bits) noexcept : bits(bits) {}
inline constexpr operator uint16_t() const noexcept { return bits; }
// Set the color values using RGB555 components that are assumed to be in range
void setRGB(const uint16_t r5, const uint16_t g5, const uint16_t b5) noexcept {
bits &= 0x8000;
bits |= (r5 | (g5 << 5) | (b5 << 10));
}
// Makes a color from the individual components.
// Note: the components are already assumed to be in range: 5-bits for RGB and 1-bit for semi-transparency.
static inline constexpr Color16 make(const uint16_t r5, const uint16_t g5, const uint16_t b5, const uint16_t t1) noexcept {
return Color16(r5 | (g5 << 5) | (b5 << 10) | (t1 << 15));
}
// Same as 'make' but with the semi transparency flag not set (RGB only)
static inline constexpr Color16 make(const uint16_t r5, const uint16_t g5, const uint16_t b5) noexcept {
return Color16(r5 | (g5 << 5) | (b5 << 10));
}
};
//----------------------------------------------------------------------------------------------------------------------