// 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 <typename T> 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<int> Rect;
|
typedef RectT<float> RectF;
|
|
template<typename T> struct SliceRectT : public RectT<T>
|
{
|
SliceRectT() : slice(0) {}
|
SliceRectT(const RectT<T>& rect) : RectT<T>(rect), slice(0) {}
|
SliceRectT(const RectT<T>& rect, int s) : RectT<T>(rect), slice(s) {}
|
SliceRectT(T x0, T y0, T x1, T y1, int s) : RectT<T>(x0, y0, x1, y1), slice(s) {}
|
int slice;
|
};
|
|
typedef SliceRectT<int> SliceRect;
|
typedef SliceRectT<float> 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<float> &color);
|
void write(int x, int y, const Color<float> &color);
|
void write(void *element, const Color<float> &color);
|
Color<float> read(int x, int y, int z) const;
|
Color<float> read(int x, int y) const;
|
Color<float> read(void *element) const;
|
Color<float> sample(float x, float y, float z) const;
|
Color<float> 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<float> &color, int x0, int y0, int width, int height);
|
|
Color<float> readExternal(int x, int y, int z) const;
|
Color<float> readExternal(int x, int y) const;
|
Color<float> sampleExternal(float x, float y, float z) const;
|
Color<float> sampleExternal(float x, float y) const;
|
void writeExternal(int x, int y, int z, const Color<float> &color);
|
void writeExternal(int x, int y, const Color<float> &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
|