vkdoom_m/src/rendering/polyrenderer/drawers/poly_triangle.h
2019-12-08 14:42:20 +01:00

586 lines
17 KiB
C++

/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "swrenderer/drawers/r_draw.h"
#include "swrenderer/drawers/r_thread.h"
#include "polyrenderer/drawers/screen_triangle.h"
#include "polyrenderer/math/gpu_types.h"
#include "polyrenderer/drawers/poly_vertex_shader.h"
class DCanvas;
class RenderMemory;
class PolyDrawerCommand;
class PolyInputAssembly;
class PolyDepthStencil;
struct PolyPushConstants;
enum class PolyDrawMode
{
Points,
Lines,
Triangles,
TriangleFan,
TriangleStrip
};
class PolyCommandBuffer
{
public:
PolyCommandBuffer(RenderMemory* frameMemory);
void SetViewport(int x, int y, int width, int height, DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown);
void SetInputAssembly(PolyInputAssembly *input);
void SetVertexBuffer(const void *vertices);
void SetIndexBuffer(const void *elements);
void SetLightBuffer(const void *lights);
void SetViewpointUniforms(const HWViewpointUniforms *uniforms);
void SetDepthClamp(bool on);
void SetDepthMask(bool on);
void SetDepthFunc(int func);
void SetDepthRange(float min, float max);
void SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor);
void SetColorMask(bool r, bool g, bool b, bool a);
void SetStencil(int stencilRef, int op);
void SetCulling(int mode);
void EnableStencil(bool on);
void SetScissor(int x, int y, int w, int h);
void SetRenderStyle(FRenderStyle style);
void SetTexture(int unit, void *pixels, int width, int height, bool bgra);
void SetShader(int specialEffect, int effectState, bool alphaTest);
void PushStreamData(const StreamData &data, const PolyPushConstants &constants);
void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix);
void ClearDepth(float value);
void ClearStencil(uint8_t value);
void Draw(int index, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
void DrawIndexed(int index, int count, PolyDrawMode mode = PolyDrawMode::Triangles);
void Submit();
private:
std::shared_ptr<DrawerCommandQueue> mQueue;
};
class PolyDepthStencil
{
public:
PolyDepthStencil(int width, int height) : width(width), height(height), depthbuffer(width * height), stencilbuffer(width * height) { }
int Width() const { return width; }
int Height() const { return height; }
float *DepthValues() { return depthbuffer.data(); }
uint8_t *StencilValues() { return stencilbuffer.data(); }
private:
int width;
int height;
std::vector<float> depthbuffer;
std::vector<uint8_t> stencilbuffer;
};
struct PolyPushConstants
{
int uTextureMode;
float uAlphaThreshold;
Vec2f uClipSplit;
// Lighting + Fog
float uLightLevel;
float uFogDensity;
float uLightFactor;
float uLightDist;
int uFogEnabled;
// dynamic lights
int uLightIndex;
};
class PolyInputAssembly
{
public:
virtual void Load(PolyTriangleThreadData *thread, const void *vertices, int index) = 0;
};
struct PolyLight
{
uint32_t color;
float x, y, z;
float radius;
};
class PolyTriangleThreadData
{
public:
PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes, int numa_start_y, int numa_end_y)
: core(core), num_cores(num_cores), numa_node(numa_node), num_numa_nodes(num_numa_nodes), numa_start_y(numa_start_y), numa_end_y(numa_end_y)
{
}
void ClearDepth(float value);
void ClearStencil(uint8_t value);
void SetViewport(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra, PolyDepthStencil *depthstencil, bool topdown);
void SetCullCCW(bool value) { ccw = value; }
void SetTwoSided(bool value) { twosided = value; }
void SetInputAssembly(PolyInputAssembly *input) { inputAssembly = input; }
void SetVertexBuffer(const void *data) { vertices = data; }
void SetIndexBuffer(const void *data) { elements = (const unsigned int *)data; }
void SetLightBuffer(const void *data) { lights = (const FVector4 *)data; }
void SetViewpointUniforms(const HWViewpointUniforms *uniforms);
void SetDepthClamp(bool on);
void SetDepthMask(bool on);
void SetDepthFunc(int func);
void SetDepthRange(float min, float max);
void SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor);
void SetColorMask(bool r, bool g, bool b, bool a);
void SetStencil(int stencilRef, int op);
void SetCulling(int mode);
void EnableStencil(bool on);
void SetScissor(int x, int y, int w, int h);
void SetRenderStyle(FRenderStyle style);
void SetTexture(int unit, const void *pixels, int width, int height, bool bgra);
void SetShader(int specialEffect, int effectState, bool alphaTest);
void UpdateClip();
void PushStreamData(const StreamData &data, const PolyPushConstants &constants);
void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix);
void DrawIndexed(int index, int count, PolyDrawMode mode);
void Draw(int index, int vcount, PolyDrawMode mode);
int32_t core;
int32_t num_cores;
int32_t numa_node;
int32_t num_numa_nodes;
int numa_start_y;
int numa_end_y;
bool line_skipped_by_thread(int line)
{
return line < numa_start_y || line >= numa_end_y || line % num_cores != core;
}
int skipped_by_thread(int first_line)
{
int clip_first_line = MAX(first_line, numa_start_y);
int core_skip = (num_cores - (clip_first_line - core) % num_cores) % num_cores;
return clip_first_line + core_skip - first_line;
}
int count_for_thread(int first_line, int count)
{
count = MIN(count, numa_end_y - first_line);
int c = (count - skipped_by_thread(first_line) + num_cores - 1) / num_cores;
return MAX(c, 0);
}
struct Scanline
{
float W[MAXWIDTH];
float WeightV1[MAXWIDTH];
float WeightV2[MAXWIDTH];
uint16_t U[MAXWIDTH];
uint16_t V[MAXWIDTH];
float WorldX[MAXWIDTH];
float WorldY[MAXWIDTH];
float WorldZ[MAXWIDTH];
uint8_t vColorA[MAXWIDTH];
uint8_t vColorR[MAXWIDTH];
uint8_t vColorG[MAXWIDTH];
uint8_t vColorB[MAXWIDTH];
float GradientdistZ[MAXWIDTH];
uint32_t FragColor[MAXWIDTH];
uint16_t lightarray[MAXWIDTH];
uint32_t dynlights[MAXWIDTH];
uint8_t discard[MAXWIDTH];
} scanline;
static PolyTriangleThreadData *Get(DrawerThread *thread);
int dest_pitch = 0;
int dest_width = 0;
int dest_height = 0;
bool dest_bgra = false;
uint8_t *dest = nullptr;
PolyDepthStencil *depthstencil = nullptr;
bool topdown = true;
float depthbias = 0.0f;
int viewport_y = 0;
struct ClipRect
{
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
} clip, scissor;
FRenderStyle RenderStyle;
int SpecialEffect = EFF_NONE;
int EffectState = 0;
bool AlphaTest = false;
uint32_t AlphaThreshold = 0x7f000000;
const PolyPushConstants* PushConstants = nullptr;
const void *vertices = nullptr;
const unsigned int *elements = nullptr;
const FVector4 *lights = nullptr;
enum { maxPolyLights = 16 };
PolyLight polyLights[maxPolyLights];
int numPolyLights = 0;
PolyMainVertexShader mainVertexShader;
struct TextureUnit
{
const void* pixels = nullptr;
int width = 0;
int height = 0;
bool bgra = true;
} textures[16];
bool DepthTest = false;
bool StencilTest = true;
bool WriteStencil = true;
bool WriteColor = true;
bool WriteDepth = true;
uint8_t StencilTestValue = 0;
uint8_t StencilWriteValue = 0;
void (*WriteColorFunc)(int y, int x0, int x1, PolyTriangleThreadData* thread) = nullptr;
private:
ShadedTriVertex ShadeVertex(int index);
void DrawShadedPoint(const ShadedTriVertex *const* vertex);
void DrawShadedLine(const ShadedTriVertex *const* vertices);
void DrawShadedTriangle(const ShadedTriVertex *const* vertices, bool ccw);
static bool IsDegenerate(const ShadedTriVertex *const* vertices);
static bool IsFrontfacing(TriDrawTriangleArgs *args);
int ClipEdge(const ShadedTriVertex *const* verts);
int viewport_x = 0;
int viewport_width = 0;
int viewport_height = 0;
bool ccw = true;
bool twosided = true;
PolyInputAssembly *inputAssembly = nullptr;
enum { max_additional_vertices = 16 };
float weightsbuffer[max_additional_vertices * 3 * 2];
float *weights = nullptr;
};
class PolyDrawerCommand : public DrawerCommand
{
public:
};
class PolySetDepthClampCommand : public PolyDrawerCommand
{
public:
PolySetDepthClampCommand(bool on) : on(on) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthClamp(on); }
private:
bool on;
};
class PolySetDepthMaskCommand : public PolyDrawerCommand
{
public:
PolySetDepthMaskCommand(bool on) : on(on) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthMask(on); }
private:
bool on;
};
class PolySetDepthFuncCommand : public PolyDrawerCommand
{
public:
PolySetDepthFuncCommand(int func) : func(func) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthFunc(func); }
private:
int func;
};
class PolySetDepthRangeCommand : public PolyDrawerCommand
{
public:
PolySetDepthRangeCommand(float min, float max) : min(min), max(max) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthRange(min, max); }
private:
float min;
float max;
};
class PolySetDepthBiasCommand : public PolyDrawerCommand
{
public:
PolySetDepthBiasCommand(float depthBiasConstantFactor, float depthBiasSlopeFactor) : depthBiasConstantFactor(depthBiasConstantFactor), depthBiasSlopeFactor(depthBiasSlopeFactor) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthBias(depthBiasConstantFactor, depthBiasSlopeFactor); }
private:
float depthBiasConstantFactor;
float depthBiasSlopeFactor;
};
class PolySetColorMaskCommand : public PolyDrawerCommand
{
public:
PolySetColorMaskCommand(bool r, bool g, bool b, bool a) : r(r), g(g), b(b), a(a) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetColorMask(r, g, b, a); }
private:
bool r;
bool g;
bool b;
bool a;
};
class PolySetStencilCommand : public PolyDrawerCommand
{
public:
PolySetStencilCommand(int stencilRef, int op) : stencilRef(stencilRef), op(op) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetStencil(stencilRef, op); }
private:
int stencilRef;
int op;
};
class PolySetCullingCommand : public PolyDrawerCommand
{
public:
PolySetCullingCommand(int mode) : mode(mode) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetCulling(mode); }
private:
int mode;
};
class PolyEnableStencilCommand : public PolyDrawerCommand
{
public:
PolyEnableStencilCommand(bool on) : on(on) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->EnableStencil(on); }
private:
bool on;
};
class PolySetScissorCommand : public PolyDrawerCommand
{
public:
PolySetScissorCommand(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetScissor(x, y, w, h); }
private:
int x;
int y;
int w;
int h;
};
class PolySetRenderStyleCommand : public PolyDrawerCommand
{
public:
PolySetRenderStyleCommand(FRenderStyle style) : style(style) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetRenderStyle(style); }
private:
FRenderStyle style;
};
class PolySetTextureCommand : public PolyDrawerCommand
{
public:
PolySetTextureCommand(int unit, void *pixels, int width, int height, bool bgra) : unit(unit), pixels(pixels), width(width), height(height), bgra(bgra) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetTexture(unit, pixels, width, height, bgra); }
private:
int unit;
void *pixels;
int width;
int height;
bool bgra;
};
class PolySetShaderCommand : public PolyDrawerCommand
{
public:
PolySetShaderCommand(int specialEffect, int effectState, bool alphaTest) : specialEffect(specialEffect), effectState(effectState), alphaTest(alphaTest) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetShader(specialEffect, effectState, alphaTest); }
private:
int specialEffect;
int effectState;
bool alphaTest;
};
class PolySetVertexBufferCommand : public PolyDrawerCommand
{
public:
PolySetVertexBufferCommand(const void *vertices) : vertices(vertices) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetVertexBuffer(vertices); }
private:
const void *vertices;
};
class PolySetIndexBufferCommand : public PolyDrawerCommand
{
public:
PolySetIndexBufferCommand(const void *indices) : indices(indices) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetIndexBuffer(indices); }
private:
const void *indices;
};
class PolySetLightBufferCommand : public PolyDrawerCommand
{
public:
PolySetLightBufferCommand(const void *lights) : lights(lights) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetLightBuffer(lights); }
private:
const void *lights;
};
class PolySetInputAssemblyCommand : public PolyDrawerCommand
{
public:
PolySetInputAssemblyCommand(PolyInputAssembly *input) : input(input) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetInputAssembly(input); }
private:
PolyInputAssembly *input;
};
class PolyClearDepthCommand : public PolyDrawerCommand
{
public:
PolyClearDepthCommand(float value) : value(value) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->ClearDepth(value); }
private:
float value;
};
class PolyClearStencilCommand : public PolyDrawerCommand
{
public:
PolyClearStencilCommand(uint8_t value) : value(value) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->ClearStencil(value); }
private:
uint8_t value;
};
class PolySetViewportCommand : public PolyDrawerCommand
{
public:
PolySetViewportCommand(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra, PolyDepthStencil *depthstencil, bool topdown)
: x(x), y(y), width(width), height(height), dest(dest), dest_width(dest_width), dest_height(dest_height), dest_pitch(dest_pitch), dest_bgra(dest_bgra), depthstencil(depthstencil), topdown(topdown) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetViewport(x, y, width, height, dest, dest_width, dest_height, dest_pitch, dest_bgra, depthstencil, topdown); }
private:
int x;
int y;
int width;
int height;
uint8_t *dest;
int dest_width;
int dest_height;
int dest_pitch;
bool dest_bgra;
PolyDepthStencil *depthstencil;
bool topdown;
};
class PolySetViewpointUniformsCommand : public PolyDrawerCommand
{
public:
PolySetViewpointUniformsCommand(const HWViewpointUniforms *uniforms) : uniforms(uniforms) {}
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetViewpointUniforms(uniforms); }
private:
const HWViewpointUniforms *uniforms;
};
class PolyPushMatricesCommand : public PolyDrawerCommand
{
public:
PolyPushMatricesCommand(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix)
: modelMatrix(modelMatrix), normalModelMatrix(normalModelMatrix), textureMatrix(textureMatrix) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->PushMatrices(modelMatrix, normalModelMatrix, textureMatrix); }
private:
VSMatrix modelMatrix;
VSMatrix normalModelMatrix;
VSMatrix textureMatrix;
};
class PolyPushStreamDataCommand : public PolyDrawerCommand
{
public:
PolyPushStreamDataCommand(const StreamData &data, const PolyPushConstants &constants) : data(data), constants(constants) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->PushStreamData(data, constants); }
private:
StreamData data;
PolyPushConstants constants;
};
class PolyDrawCommand : public PolyDrawerCommand
{
public:
PolyDrawCommand(int index, int count, PolyDrawMode mode) : index(index), count(count), mode(mode) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->Draw(index, count, mode); }
private:
int index;
int count;
PolyDrawMode mode;
};
class PolyDrawIndexedCommand : public PolyDrawerCommand
{
public:
PolyDrawIndexedCommand(int index, int count, PolyDrawMode mode) : index(index), count(count), mode(mode) { }
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->DrawIndexed(index, count, mode); }
private:
int index;
int count;
PolyDrawMode mode;
};