#ifndef __MDFN_SURFACE_H #define __MDFN_SURFACE_H struct MDFN_Rect { int32 x, y, w, h; }; enum { MDFN_COLORSPACE_RGB = 0, //MDFN_COLORSPACE_LRGB = 1, // Linear RGB, 16-bit per component, TODO in the future? //MDFN_COLORSPACE_YUV = 2, // TODO, maybe. }; struct MDFN_PaletteEntry { uint8 r, g, b; }; /* template static constexpr INLINE uint64 MDFN_PixelFormat_SetTagT(const uint64 tag) { return (tag & ~0xFF) | (sizeof(T) * 8); } */ static constexpr INLINE uint64 MDFN_PixelFormat_MakeTag(const uint8 colorspace, const uint8 opp, const uint8 rs, const uint8 gs, const uint8 bs, const uint8 as, const uint8 rp, const uint8 gp, const uint8 bp, const uint8 ap) { // (8 * 6) = 48 return ((uint64)colorspace << 56) | ((uint64)opp << 48) | ((uint64)rs << (0 * 6)) | ((uint64)gs << (1 * 6)) | ((uint64)bs << (2 * 6)) | ((uint64)as << (3 * 6)) | ((uint64)rp << (4 * 6)) | ((uint64)gp << (5 * 6)) | ((uint64)bp << (6 * 6)) | ((uint64)ap << (7 * 6)); } class MDFN_PixelFormat { public: // // MDFN_PixelFormat constructors must remain inline for various code to be optimized // properly by the compiler. // INLINE MDFN_PixelFormat(const uint64 tag_) : tag(tag_), colorspace((uint8)(tag_ >> 56)), opp((uint8)(tag_ >> 48)), Rshift((tag_ >> (0 * 6)) & 0x3F), Gshift((tag_ >> (1 * 6)) & 0x3F), Bshift((tag_ >> (2 * 6)) & 0x3F), Ashift((tag_ >> (3 * 6)) & 0x3F), Rprec((tag_ >> (4 * 6)) & 0x3F), Gprec((tag_ >> (5 * 6)) & 0x3F), Bprec((tag_ >> (6 * 6)) & 0x3F), Aprec((tag_ >> (7 * 6)) & 0x3F) { // } INLINE MDFN_PixelFormat() : tag(0), colorspace(0), opp(0), Rshift(0), Gshift(0), Bshift(0), Ashift(0), Rprec(0), Gprec(0), Bprec(0), Aprec(0) { // } INLINE MDFN_PixelFormat(const unsigned int colorspace_, const uint8 opp_, const uint8 rs, const uint8 gs, const uint8 bs, const uint8 as, const uint8 rp = 8, const uint8 gp = 8, const uint8 bp = 8, const uint8 ap = 8) : tag(MDFN_PixelFormat_MakeTag(colorspace_, opp_, rs, gs, bs, as, rp, gp, bp, ap)), colorspace(colorspace_), opp(opp_), Rshift(rs), Gshift(gs), Bshift(bs), Ashift(as), Rprec(rp), Gprec(gp), Bprec(bp), Aprec(ap) { // } //constexpr MDFN_PixelFormat(MDFN_PixelFormat&) = default; //constexpr MDFN_PixelFormat(MDFN_PixelFormat&&) = default; //MDFN_PixelFormat& operator=(MDFN_PixelFormat&) = default; bool operator==(const uint64& t) { return tag == t; } bool operator==(const MDFN_PixelFormat& a) { return tag == a.tag; } bool operator!=(const MDFN_PixelFormat& a) { return !(*this == a); } uint64 tag; uint8 colorspace; uint8 opp; // Bytes per pixel; 1, 2, 4 (1 is WIP) uint8 Rshift; // Bit position of the lowest bit of the red component uint8 Gshift; // [...] green component uint8 Bshift; // [...] blue component uint8 Ashift; // [...] alpha component. // For 16bpp, WIP uint8 Rprec; uint8 Gprec; uint8 Bprec; uint8 Aprec; // Creates a color value for the surface corresponding to the 8-bit R/G/B/A color passed. INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const { if(opp == 2) { uint32 ret; ret = ((r * ((1 << Rprec) - 1) + 127) / 255) << Rshift; ret |= ((g * ((1 << Gprec) - 1) + 127) / 255) << Gshift; ret |= ((b * ((1 << Bprec) - 1) + 127) / 255) << Bshift; ret |= ((a * ((1 << Aprec) - 1) + 127) / 255) << Ashift; return ret; } else return (r << Rshift) | (g << Gshift) | (b << Bshift) | (a << Ashift); } INLINE MDFN_PaletteEntry MakePColor(uint8 r, uint8 g, uint8 b) const { MDFN_PaletteEntry ret; ret.r = ((r * ((1 << Rprec) - 1) + 127) / 255) << Rshift; ret.g = ((g * ((1 << Gprec) - 1) + 127) / 255) << Gshift; ret.b = ((b * ((1 << Bprec) - 1) + 127) / 255) << Bshift; return ret; } INLINE void DecodePColor(const MDFN_PaletteEntry& pe, uint8 &r, uint8 &g, uint8 &b) const { r = ((pe.r >> Rshift) & ((1 << Rprec) - 1)) * 255 / ((1 << Rprec) - 1); g = ((pe.g >> Gshift) & ((1 << Gprec) - 1)) * 255 / ((1 << Gprec) - 1); b = ((pe.b >> Bshift) & ((1 << Bprec) - 1)) * 255 / ((1 << Bprec) - 1); } // Gets the R/G/B/A values for the passed 32-bit surface pixel value INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const { if(opp == 2) { r = ((value >> Rshift) & ((1 << Rprec) - 1)) * 255 / ((1 << Rprec) - 1); g = ((value >> Gshift) & ((1 << Gprec) - 1)) * 255 / ((1 << Gprec) - 1); b = ((value >> Bshift) & ((1 << Bprec) - 1)) * 255 / ((1 << Bprec) - 1); a = ((value >> Ashift) & ((1 << Aprec) - 1)) * 255 / ((1 << Aprec) - 1); } else { r = (value >> Rshift) & 0xFF; g = (value >> Gshift) & 0xFF; b = (value >> Bshift) & 0xFF; a = (value >> Ashift) & 0xFF; } } MDFN_HIDE static const uint8 LUT5to8[32]; MDFN_HIDE static const uint8 LUT6to8[64]; MDFN_HIDE static const uint8 LUT8to5[256]; MDFN_HIDE static const uint8 LUT8to6[256]; INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const { int dummy_a; DecodeColor(value, r, g, b, dummy_a); } static INLINE void TDecodeColor(uint64 tag, uint32 c, int* r, int* g, int* b) { if(tag == IRGB16_1555) { *r = LUT5to8[(c >> 10) & 0x1F]; *g = LUT5to8[(c >> 5) & 0x1F]; *b = LUT5to8[(c >> 0) & 0x1F]; //*a = 0; } else if(tag == RGB16_565) { *r = LUT5to8[(c >> 11) & 0x1F]; *g = LUT6to8[(c >> 5) & 0x3F]; *b = LUT5to8[(c >> 0) & 0x1F]; //*a = 0; } else { MDFN_PixelFormat pf = tag; pf.DecodeColor(c, *r, *g, *b); } } static INLINE uint32 TMakeColor(uint64 tag, uint8 r, uint8 g, uint8 b) { if(tag == IRGB16_1555) return (LUT8to5[r] << 10) | (LUT8to5[g] << 5) | (LUT8to5[b] << 0); else if(tag == RGB16_565) return (LUT8to5[r] << 11) | (LUT8to6[g] << 5) | (LUT8to5[b] << 0); else { MDFN_PixelFormat pf = tag; return pf.MakeColor(r, g, b); } } enum : uint64 { // // All 24 possible RGB-colorspace xxxx32_8888 formats are supported by core Mednafen and emulation modules, // but the ones not enumerated here will be less performant. // // In regards to emulation modules' video output, the alpha channel is for internal use, // and should be ignored by driver-side/frontend code. // ABGR32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 0, 8, 16, 24, /**/ 8, 8, 8, 8), ARGB32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 16, 8, 0, 24, /**/ 8, 8, 8, 8), RGBA32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 24, 16, 8, 0, /**/ 8, 8, 8, 8), BGRA32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 8, 16, 24, 0, /**/ 8, 8, 8, 8), // // These two RGB16 formats are the only 16-bit formats fully supported by core Mednafen code, // and most emulation modules(also see MDFNGI::ExtraVideoFormatSupport) // // Alpha shift/precision weirdness for internal emulation module use. // IRGB16_1555 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 10, 5, 0, 16, /**/ 5, 5, 5, 8), RGB16_565 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 11, 5, 0, 16, /**/ 5, 6, 5, 8), // // Following formats are not supported by emulation modules, and only partially supported by core // Mednafen code: // ARGB16_4444 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 8, 4, 0, 12, /**/ 4, 4, 4, 4), // // TODO: Following two hackyish formats are only valid when used as a destination pixel format with // MDFN_PixelFormatConverter // // RGB8X3_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 3, /**/ 0, 1, 2, 0, /**/ 8, 8, 8, 0), // BGR8X3_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 3, /**/ 2, 1, 0, 0, /**/ 8, 8, 8, 0), // // TODO: //RGB8P_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 1, /**/ 0, 0, 0, 8, /**/ 8, 8, 8, 0), //RGB8P_666 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 1, /**/ 0, 0, 0, 8, /**/ 6, 6, 6, 0), }; }; // MDFN_PixelFormat; // 8bpp support is incomplete class MDFN_Surface { public: MDFN_Surface(); MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels = true); ~MDFN_Surface(); uint8 *pixels8; uint16 *pixels16; uint32 *pixels; template T* pix(void) { if(sizeof(T) == 1) return (T*)pixels8; else if(sizeof(T) == 2) return (T*)pixels16; else if(sizeof(T) == 4) return (T*)pixels; else return NULL; } MDFN_PaletteEntry *palette; bool pixels_is_external; // w, h, and pitch32 should always be > 0 int32 w; int32 h; union { int32 pitch32; // In pixels, not in bytes. int32 pitchinpix; // New name, new code should use this. }; MDFN_PixelFormat format; void Fill(uint8 r, uint8 g, uint8 b, uint8 a); void SetFormat(const MDFN_PixelFormat &new_format, bool convert); // Creates a 32-bit value for the surface corresponding to the R/G/B/A color passed. INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const { return(format.MakeColor(r, g, b, a)); } // Gets the R/G/B/A values for the passed 32-bit surface pixel value INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const { format.DecodeColor(value, r, g, b, a); } INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const { int dummy_a; DecodeColor(value, r, g, b, dummy_a); } private: void Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels); }; #endif