// 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 "Device/Config.hpp" #include "System/Resource.hpp" #include <vulkan/vulkan.h> 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 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 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; VkFormat format; AtomicInt lock; bool dirty; // Sibling internal/external buffer doesn't match. }; protected: Surface(int width, int height, int depth, VkFormat format, void *pixels, int pitch, int slice); Surface(Resource *texture, int width, int height, int depth, int border, int samples, VkFormat format, bool lockable, bool renderTarget, int pitchP = 0); public: static Surface *create(int width, int height, int depth, VkFormat format, void *pixels, int pitch, int slice); static Surface *create(Resource *texture, int width, int height, int depth, int border, int samples, VkFormat 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 VkFormat 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 VkFormat 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 VkFormat 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 VkFormat 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 isRenderTarget() const; bool hasDirtyContents() const; void markContentsClean(); inline bool isExternalDirty() const; Resource *getResource(); static int bytes(VkFormat format); static int pitchB(int width, int border, VkFormat format, bool target); static int pitchP(int width, int border, VkFormat format, bool target); static int sliceB(int width, int height, int border, VkFormat format, bool target); static int sliceP(int width, int height, int border, VkFormat format, bool target); static size_t size(int width, int height, int depth, int border, int samples, VkFormat format); static bool isStencil(VkFormat format); static bool isDepth(VkFormat format); static bool hasQuadLayout(VkFormat format); static bool isFloatFormat(VkFormat format); static bool isUnsignedComponent(VkFormat format, int component); static bool isSRGBreadable(VkFormat format); static bool isSRGBwritable(VkFormat format); static bool isSRGBformat(VkFormat format); static bool isCompressed(VkFormat format); static bool isSignedNonNormalizedInteger(VkFormat format); static bool isUnsignedNonNormalizedInteger(VkFormat format); static bool isNonNormalizedInteger(VkFormat format); static bool isNormalizedInteger(VkFormat format); static int componentCount(VkFormat format); 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 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, VkFormat format); static void memfill4(void *buffer, int pattern, int bytes); bool identicalBuffers() const; VkFormat selectInternalFormat(VkFormat 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). 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; } VkFormat 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(); } VkFormat 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; } VkFormat 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; } VkFormat 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