|  | // 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_core.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 |