blob: b9fc7c708a995e1bc7de383eeb464746428030d1 [file] [log] [blame]
// 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_Blitter_hpp
#define sw_Blitter_hpp
#include "Memset.hpp"
#include "RoutineCache.hpp"
#include "Reactor/Reactor.hpp"
#include "Vulkan/VkFormat.hpp"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <cstring>
namespace vk {
class Image;
class ImageView;
class Buffer;
} // namespace vk
namespace sw {
class Blitter
{
struct Options
{
explicit Options() = default;
explicit Options(bool filter, bool allowSRGBConversion)
: writeMask(0xF)
, clearOperation(false)
, filter(filter)
, allowSRGBConversion(allowSRGBConversion)
, clampToEdge(false)
{}
explicit Options(unsigned int writeMask)
: writeMask(writeMask)
, clearOperation(true)
, filter(false)
, allowSRGBConversion(true)
, clampToEdge(false)
{}
union
{
struct
{
bool writeRed : 1;
bool writeGreen : 1;
bool writeBlue : 1;
bool writeAlpha : 1;
};
unsigned char writeMask;
};
bool clearOperation : 1;
bool filter : 1;
bool allowSRGBConversion : 1;
bool clampToEdge : 1;
};
struct State : Memset<State>, Options
{
State()
: Memset(this, 0)
{}
State(const Options &options)
: Memset(this, 0)
, Options(options)
{}
State(vk::Format sourceFormat, vk::Format destFormat, int srcSamples, int destSamples, const Options &options)
: Memset(this, 0)
, Options(options)
, sourceFormat(sourceFormat)
, destFormat(destFormat)
, srcSamples(srcSamples)
, destSamples(destSamples)
{}
vk::Format sourceFormat;
vk::Format destFormat;
int srcSamples = 0;
int destSamples = 0;
bool filter3D = false;
};
friend std::hash<Blitter::State>;
struct BlitData
{
void *source;
void *dest;
int sPitchB;
int dPitchB;
int sSliceB;
int dSliceB;
float x0;
float y0;
float z0;
float w;
float h;
float d;
int x0d;
int x1d;
int y0d;
int y1d;
int z0d;
int z1d;
int sWidth;
int sHeight;
int sDepth;
bool filter3D;
};
struct CubeBorderData
{
void *layers;
int pitchB;
uint32_t layerSize;
uint32_t dim;
};
public:
Blitter();
virtual ~Blitter();
void clear(void *clearValue, vk::Format clearFormat, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea = nullptr);
void blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter);
void resolve(const vk::Image *src, vk::Image *dst, VkImageResolve region);
void resolveDepthStencil(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc);
void copy(const vk::Image *src, uint8_t *dst, unsigned int dstPitch);
void updateBorders(vk::Image *image, const VkImageSubresource &subresource);
private:
enum Edge
{
TOP,
BOTTOM,
RIGHT,
LEFT
};
bool fastClear(void *clearValue, vk::Format clearFormat, vk::Image *dest, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D *renderArea);
bool fastResolve(const vk::Image *src, vk::Image *dst, VkImageResolve region);
Float4 readFloat4(Pointer<Byte> element, const State &state);
void write(Float4 &color, Pointer<Byte> element, const State &state);
Int4 readInt4(Pointer<Byte> element, const State &state);
void write(Int4 &color, Pointer<Byte> element, const State &state);
static void ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled = false);
static Int ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes);
static Int ComputeOffset(Int &x, Int &y, Int &z, Int &sliceB, Int &pitchB, int bytes);
static Float4 LinearToSRGB(const Float4 &color);
static Float4 sRGBtoLinear(const Float4 &color);
using BlitFunction = FunctionT<void(const BlitData *)>;
using BlitRoutineType = BlitFunction::RoutineType;
BlitRoutineType getBlitRoutine(const State &state);
BlitRoutineType generate(const State &state);
Float4 sample(Pointer<Byte> &source, Float &x, Float &y, Float &z,
Int &sWidth, Int &sHeight, Int &sDepth,
Int &sSliceB, Int &sPitchB, const State &state);
using CornerUpdateFunction = FunctionT<void(const CubeBorderData *)>;
using CornerUpdateRoutineType = CornerUpdateFunction::RoutineType;
CornerUpdateRoutineType getCornerUpdateRoutine(const State &state);
CornerUpdateRoutineType generateCornerUpdate(const State &state);
void computeCubeCorner(Pointer<Byte> &layer, Int &x0, Int &x1, Int &y0, Int &y1, Int &pitchB, const State &state);
void copyCubeEdge(vk::Image *image,
const VkImageSubresource &dstSubresource, Edge dstEdge,
const VkImageSubresource &srcSubresource, Edge srcEdge);
marl::mutex blitMutex;
RoutineCache<State, BlitFunction::CFunctionType> blitCache GUARDED_BY(blitMutex);
marl::mutex cornerUpdateMutex;
RoutineCache<State, CornerUpdateFunction::CFunctionType> cornerUpdateCache GUARDED_BY(cornerUpdateMutex);
};
} // namespace sw
namespace std {
template<>
struct hash<sw::Blitter::State>
{
uint64_t operator()(const sw::Blitter::State &state) const
{
uint64_t hash = state.sourceFormat;
hash = hash * 31 + state.destFormat;
hash = hash * 31 + state.srcSamples;
hash = hash * 31 + state.destSamples;
hash = hash * 31 + state.filter3D;
return hash;
}
};
} // namespace std
#endif // sw_Blitter_hpp