// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef sw_Surface_hpp #define sw_Surface_hpp #include "Color.hpp" #include "Main/Config.hpp" #include "Common/Resource.hpp" namespace sw { class Resource; template struct RectT { RectT() {} RectT(T x0i, T y0i, T x1i, T y1i) : x0(x0i), y0(y0i), x1(x1i), y1(y1i) {} void clip(T minX, T minY, T maxX, T maxY) { x0 = clamp(x0, minX, maxX); y0 = clamp(y0, minY, maxY); x1 = clamp(x1, minX, maxX); y1 = clamp(y1, minY, maxY); } T width() const { return x1 - x0; } T height() const { return y1 - y0; } T x0; // Inclusive T y0; // Inclusive T x1; // Exclusive T y1; // Exclusive }; typedef RectT Rect; typedef RectT RectF; template struct SliceRectT : public RectT { SliceRectT() : slice(0) {} SliceRectT(const RectT& rect) : RectT(rect), slice(0) {} SliceRectT(const RectT& rect, int s) : RectT(rect), slice(s) {} SliceRectT(T x0, T y0, T x1, T y1, int s) : RectT(x0, y0, x1, y1), slice(s) {} int slice; }; typedef SliceRectT SliceRect; typedef SliceRectT SliceRectF; enum Format : unsigned char { FORMAT_NULL, FORMAT_A8, FORMAT_R8I, FORMAT_R8UI, FORMAT_R8_SNORM, FORMAT_R8, FORMAT_R16I, FORMAT_R16UI, FORMAT_R32I, FORMAT_R32UI, FORMAT_R3G3B2, FORMAT_A8R3G3B2, FORMAT_X4R4G4B4, FORMAT_A4R4G4B4, FORMAT_R4G4B4A4, FORMAT_R5G6B5, FORMAT_R8G8B8, FORMAT_B8G8R8, FORMAT_X8R8G8B8, FORMAT_A8R8G8B8, FORMAT_X8B8G8R8I, FORMAT_X8B8G8R8UI, FORMAT_X8B8G8R8_SNORM, FORMAT_X8B8G8R8, FORMAT_A8B8G8R8I, FORMAT_A8B8G8R8UI, FORMAT_A8B8G8R8_SNORM, FORMAT_A8B8G8R8, FORMAT_SRGB8_X8, FORMAT_SRGB8_A8, FORMAT_X1R5G5B5, FORMAT_A1R5G5B5, FORMAT_R5G5B5A1, FORMAT_G8R8I, FORMAT_G8R8UI, FORMAT_G8R8_SNORM, FORMAT_G8R8, FORMAT_G16R16, FORMAT_G16R16I, FORMAT_G16R16UI, FORMAT_G32R32I, FORMAT_G32R32UI, FORMAT_A2R10G10B10, FORMAT_A2B10G10R10, FORMAT_A2B10G10R10UI, FORMAT_A16B16G16R16, FORMAT_X16B16G16R16I, FORMAT_X16B16G16R16UI, FORMAT_A16B16G16R16I, FORMAT_A16B16G16R16UI, FORMAT_X32B32G32R32I, FORMAT_X32B32G32R32UI, FORMAT_A32B32G32R32I, FORMAT_A32B32G32R32UI, // Paletted formats FORMAT_P8, FORMAT_A8P8, // Compressed formats FORMAT_DXT1, FORMAT_DXT3, FORMAT_DXT5, FORMAT_ATI1, FORMAT_ATI2, FORMAT_ETC1, FORMAT_R11_EAC, FORMAT_SIGNED_R11_EAC, FORMAT_RG11_EAC, FORMAT_SIGNED_RG11_EAC, FORMAT_RGB8_ETC2, FORMAT_SRGB8_ETC2, FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, FORMAT_RGBA8_ETC2_EAC, FORMAT_SRGB8_ALPHA8_ETC2_EAC, FORMAT_RGBA_ASTC_4x4_KHR, FORMAT_RGBA_ASTC_5x4_KHR, FORMAT_RGBA_ASTC_5x5_KHR, FORMAT_RGBA_ASTC_6x5_KHR, FORMAT_RGBA_ASTC_6x6_KHR, FORMAT_RGBA_ASTC_8x5_KHR, FORMAT_RGBA_ASTC_8x6_KHR, FORMAT_RGBA_ASTC_8x8_KHR, FORMAT_RGBA_ASTC_10x5_KHR, FORMAT_RGBA_ASTC_10x6_KHR, FORMAT_RGBA_ASTC_10x8_KHR, FORMAT_RGBA_ASTC_10x10_KHR, FORMAT_RGBA_ASTC_12x10_KHR, FORMAT_RGBA_ASTC_12x12_KHR, FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR, FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR, FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR, FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR, FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR, FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR, FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR, FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR, FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR, FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR, FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR, FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR, FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR, FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR, // Floating-point formats FORMAT_A16F, FORMAT_R16F, FORMAT_G16R16F, FORMAT_B16G16R16F, FORMAT_X16B16G16R16F, FORMAT_A16B16G16R16F, FORMAT_X16B16G16R16F_UNSIGNED, FORMAT_A32F, FORMAT_R32F, FORMAT_G32R32F, FORMAT_B32G32R32F, FORMAT_X32B32G32R32F, FORMAT_A32B32G32R32F, FORMAT_X32B32G32R32F_UNSIGNED, // Bump map formats FORMAT_V8U8, FORMAT_L6V5U5, FORMAT_Q8W8V8U8, FORMAT_X8L8V8U8, FORMAT_A2W10V10U10, FORMAT_V16U16, FORMAT_A16W16V16U16, FORMAT_Q16W16V16U16, // Luminance formats FORMAT_L8, FORMAT_A4L4, FORMAT_L16, FORMAT_A8L8, FORMAT_L16F, FORMAT_A16L16F, FORMAT_L32F, FORMAT_A32L32F, // Depth/stencil formats FORMAT_D16, FORMAT_D32, FORMAT_D24X8, FORMAT_D24S8, FORMAT_D24FS8, FORMAT_D32F, // Quad layout FORMAT_D32FS8, // Quad layout FORMAT_D32F_COMPLEMENTARY, // Quad layout, 1 - z FORMAT_D32FS8_COMPLEMENTARY, // Quad layout, 1 - z FORMAT_D32F_LOCKABLE, // Linear layout FORMAT_D32FS8_TEXTURE, // Linear layout, no PCF FORMAT_D32F_SHADOW, // Linear layout, PCF FORMAT_D32FS8_SHADOW, // Linear layout, PCF FORMAT_DF24S8, FORMAT_DF16S8, FORMAT_INTZ, FORMAT_S8, // Quad layout framebuffer FORMAT_X8G8R8B8Q, FORMAT_A8G8R8B8Q, // YUV formats FORMAT_YV12_BT601, FORMAT_YV12_BT709, FORMAT_YV12_JFIF, // Full-swing BT.601 FORMAT_LAST = FORMAT_YV12_JFIF }; enum Lock { LOCK_UNLOCKED, LOCK_READONLY, LOCK_WRITEONLY, LOCK_READWRITE, LOCK_DISCARD, LOCK_UPDATE // Write access which doesn't dirty the buffer, because it's being updated with the sibling's data. }; class [[clang::lto_visibility_public]] Surface { private: struct Buffer { friend Surface; private: void write(int x, int y, int z, const Color &color); void write(int x, int y, const Color &color); void write(void *element, const Color &color); Color read(int x, int y, int z) const; Color read(int x, int y) const; Color read(void *element) const; Color sample(float x, float y, float z) const; Color sample(float x, float y, int layer) const; void *lockRect(int x, int y, int z, Lock lock); void unlockRect(); void *buffer; int width; int height; int depth; short border; short samples; int bytes; int pitchB; int pitchP; int sliceB; int sliceP; Format format; AtomicInt lock; bool dirty; // Sibling internal/external buffer doesn't match. }; protected: Surface(int width, int height, int depth, Format format, void *pixels, int pitch, int slice); Surface(Resource *texture, int width, int height, int depth, int border, int samples, Format format, bool lockable, bool renderTarget, int pitchP = 0); public: static Surface *create(int width, int height, int depth, Format format, void *pixels, int pitch, int slice); static Surface *create(Resource *texture, int width, int height, int depth, int border, int samples, Format format, bool lockable, bool renderTarget, int pitchP = 0); virtual ~Surface() = 0; inline void *lock(int x, int y, int z, Lock lock, Accessor client, bool internal = false); inline void unlock(bool internal = false); inline int getWidth() const; inline int getHeight() const; inline int getDepth() const; inline int getBorder() const; inline Format getFormat(bool internal = false) const; inline int getPitchB(bool internal = false) const; inline int getPitchP(bool internal = false) const; inline int getSliceB(bool internal = false) const; inline int getSliceP(bool internal = false) const; void *lockExternal(int x, int y, int z, Lock lock, Accessor client); void unlockExternal(); inline Format getExternalFormat() const; inline int getExternalPitchB() const; inline int getExternalPitchP() const; inline int getExternalSliceB() const; inline int getExternalSliceP() const; virtual void *lockInternal(int x, int y, int z, Lock lock, Accessor client) = 0; virtual void unlockInternal() = 0; inline Format getInternalFormat() const; inline int getInternalPitchB() const; inline int getInternalPitchP() const; inline int getInternalSliceB() const; inline int getInternalSliceP() const; void *lockStencil(int x, int y, int front, Accessor client); void unlockStencil(); inline Format getStencilFormat() const; inline int getStencilPitchB() const; inline int getStencilSliceB() const; void sync(); // Wait for lock(s) to be released. virtual bool requiresSync() const { return false; } inline bool isUnlocked() const; // Only reliable after sync(). inline int getSamples() const; inline int getMultiSampleCount() const; inline int getSuperSampleCount() const; bool isEntire(const Rect& rect) const; Rect getRect() const; void clearDepth(float depth, int x0, int y0, int width, int height); void clearStencil(unsigned char stencil, unsigned char mask, int x0, int y0, int width, int height); void fill(const Color &color, int x0, int y0, int width, int height); Color readExternal(int x, int y, int z) const; Color readExternal(int x, int y) const; Color sampleExternal(float x, float y, float z) const; Color sampleExternal(float x, float y) const; void writeExternal(int x, int y, int z, const Color &color); void writeExternal(int x, int y, const Color &color); void copyInternal(const Surface* src, int x, int y, float srcX, float srcY, bool filter); void copyInternal(const Surface* src, int x, int y, int z, float srcX, float srcY, float srcZ, bool filter); enum Edge { TOP, BOTTOM, RIGHT, LEFT }; void copyCubeEdge(Edge dstEdge, Surface *src, Edge srcEdge); void computeCubeCorner(int x0, int y0, int x1, int y1); bool hasStencil() const; bool hasDepth() const; bool hasPalette() const; bool isRenderTarget() const; bool hasDirtyContents() const; void markContentsClean(); inline bool isExternalDirty() const; Resource *getResource(); static int bytes(Format format); static int pitchB(int width, int border, Format format, bool target); static int pitchP(int width, int border, Format format, bool target); static int sliceB(int width, int height, int border, Format format, bool target); static int sliceP(int width, int height, int border, Format format, bool target); static size_t size(int width, int height, int depth, int border, int samples, Format format); static bool isStencil(Format format); static bool isDepth(Format format); static bool hasQuadLayout(Format format); static bool isPalette(Format format); static bool isFloatFormat(Format format); static bool isUnsignedComponent(Format format, int component); static bool isSRGBreadable(Format format); static bool isSRGBwritable(Format format); static bool isSRGBformat(Format format); static bool isCompressed(Format format); static bool isSignedNonNormalizedInteger(Format format); static bool isUnsignedNonNormalizedInteger(Format format); static bool isNonNormalizedInteger(Format format); static bool isNormalizedInteger(Format format); static int componentCount(Format format); static void setTexturePalette(unsigned int *palette); private: sw::Resource *resource; typedef unsigned char byte; typedef unsigned short word; typedef unsigned int dword; typedef uint64_t qword; struct DXT1 { word c0; word c1; dword lut; }; struct DXT3 { qword a; word c0; word c1; dword lut; }; struct DXT5 { union { struct { byte a0; byte a1; }; qword alut; // Skip first 16 bit }; word c0; word c1; dword clut; }; struct ATI2 { union { struct { byte y0; byte y1; }; qword ylut; // Skip first 16 bit }; union { struct { byte x0; byte x1; }; qword xlut; // Skip first 16 bit }; }; struct ATI1 { union { struct { byte r0; byte r1; }; qword rlut; // Skip first 16 bit }; }; static void decodeR8G8B8(Buffer &destination, Buffer &source); static void decodeX1R5G5B5(Buffer &destination, Buffer &source); static void decodeA1R5G5B5(Buffer &destination, Buffer &source); static void decodeX4R4G4B4(Buffer &destination, Buffer &source); static void decodeA4R4G4B4(Buffer &destination, Buffer &source); static void decodeP8(Buffer &destination, Buffer &source); static void decodeDXT1(Buffer &internal, Buffer &external); static void decodeDXT3(Buffer &internal, Buffer &external); static void decodeDXT5(Buffer &internal, Buffer &external); static void decodeATI1(Buffer &internal, Buffer &external); static void decodeATI2(Buffer &internal, Buffer &external); static void decodeEAC(Buffer &internal, Buffer &external, int nbChannels, bool isSigned); static void decodeETC2(Buffer &internal, Buffer &external, int nbAlphaBits, bool isSRGB); static void decodeASTC(Buffer &internal, Buffer &external, int xSize, int ySize, int zSize, bool isSRGB); static void update(Buffer &destination, Buffer &source); static void genericUpdate(Buffer &destination, Buffer &source); static void *allocateBuffer(int width, int height, int depth, int border, int samples, Format format); static void memfill4(void *buffer, int pattern, int bytes); bool identicalBuffers() const; Format selectInternalFormat(Format format) const; void resolve(); Buffer external; Buffer internal; Buffer stencil; const bool lockable; const bool renderTarget; bool dirtyContents; // Sibling surfaces need updating (mipmaps / cube borders). unsigned int paletteUsed; static unsigned int *palette; // FIXME: Not multi-device safe static unsigned int paletteID; bool hasParent; bool ownExternal; }; } #undef min #undef max namespace sw { void *Surface::lock(int x, int y, int z, Lock lock, Accessor client, bool internal) { return internal ? lockInternal(x, y, z, lock, client) : lockExternal(x, y, z, lock, client); } void Surface::unlock(bool internal) { return internal ? unlockInternal() : unlockExternal(); } int Surface::getWidth() const { return external.width; } int Surface::getHeight() const { return external.height; } int Surface::getDepth() const { return external.depth; } int Surface::getBorder() const { return internal.border; } Format Surface::getFormat(bool internal) const { return internal ? getInternalFormat() : getExternalFormat(); } int Surface::getPitchB(bool internal) const { return internal ? getInternalPitchB() : getExternalPitchB(); } int Surface::getPitchP(bool internal) const { return internal ? getInternalPitchP() : getExternalPitchP(); } int Surface::getSliceB(bool internal) const { return internal ? getInternalSliceB() : getExternalSliceB(); } int Surface::getSliceP(bool internal) const { return internal ? getInternalSliceP() : getExternalSliceP(); } Format Surface::getExternalFormat() const { return external.format; } int Surface::getExternalPitchB() const { return external.pitchB; } int Surface::getExternalPitchP() const { return external.pitchP; } int Surface::getExternalSliceB() const { return external.sliceB; } int Surface::getExternalSliceP() const { return external.sliceP; } Format Surface::getInternalFormat() const { return internal.format; } int Surface::getInternalPitchB() const { return internal.pitchB; } int Surface::getInternalPitchP() const { return internal.pitchP; } int Surface::getInternalSliceB() const { return internal.sliceB; } int Surface::getInternalSliceP() const { return internal.sliceP; } Format Surface::getStencilFormat() const { return stencil.format; } int Surface::getStencilPitchB() const { return stencil.pitchB; } int Surface::getStencilSliceB() const { return stencil.sliceB; } int Surface::getSamples() const { return internal.samples; } int Surface::getMultiSampleCount() const { return sw::min((int)internal.samples, 4); } int Surface::getSuperSampleCount() const { return internal.samples > 4 ? internal.samples / 4 : 1; } bool Surface::isUnlocked() const { return external.lock == LOCK_UNLOCKED && internal.lock == LOCK_UNLOCKED && stencil.lock == LOCK_UNLOCKED; } bool Surface::isExternalDirty() const { return external.buffer && external.buffer != internal.buffer && external.dirty; } } #endif // sw_Surface_hpp