Skip to content

Instantly share code, notes, and snippets.

@skmp
Last active March 12, 2021 14:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skmp/fc3ae9b26f88b37706642cc23b49adca to your computer and use it in GitHub Desktop.
Save skmp/fc3ae9b26f88b37706642cc23b49adca to your computer and use it in GitHub Desktop.
FPGAdc: Getting started w/ HLS
/*******************************************************************************
What if you generated a PowerVR CLX2 ISP and TSP implementation with HLS?
Would it fit to the ultra96?
*******************************************************************************/
#include <cmath>
#include <algorithm>
#include <memory.h>
#include "refrend_hls.h"
using namespace std;
enum RenderMode {
RM_OPAQUE,
RM_PUNCHTHROUGH,
RM_TRANSLUCENT,
RM_MODIFIER,
RM_COUNT
};
int area_left, area_top, area_right, area_bottom;
struct ISP_TSP
{
u32 Reserved : 20;
u32 DCalcCtrl : 1;
u32 CacheBypass : 1;
u32 UV_16b : 1; //In TA they are replaced
u32 Gouraud : 1; //by the ones on PCW
u32 Offset : 1; //
u32 Texture : 1; // -- up to here --
u32 ZWriteDis : 1;
u32 CullMode : 2;
u32 DepthMode : 3;
};
struct ISP_Modvol
{
u32 id : 26;
u32 VolumeLast : 1;
u32 CullMode : 2;
u32 DepthMode : 3;
};
//// END ISP/TSP Instruction Word
//// TSP Instruction Word
struct TSP
{
u32 TexV : 3;
u32 TexU : 3;
u32 ShadInstr : 2;
u32 MipMapD : 4;
u32 SupSample : 1;
u32 FilterMode : 2;
u32 ClampV : 1;
u32 ClampU : 1;
u32 FlipV : 1;
u32 FlipU : 1;
u32 IgnoreTexA : 1;
u32 UseAlpha : 1;
u32 ColorClamp : 1;
u32 FogCtrl : 2;
u32 DstSelect : 1; // Secondary Accum
u32 SrcSelect : 1; // Primary Accum
u32 DstInstr : 3;
u32 SrcInstr : 3;
};
//// END TSP Instruction Word
/// Texture Control Word
struct TCW
{
u32 TexAddr :21;
u32 Reserved : 4;
u32 StrideSel : 1;
u32 ScanOrder : 1;
u32 PixelFmt : 3;
u32 VQ_Comp : 1;
u32 MipMapped : 1;
};
//Vertex storage types
struct Vertex
{
float x,y,z;
u32 col;
u32 spc;
float u,v;
// Two volumes format
u32 col1;
u32 spc1;
float u1,v1;
};
// Some global state
Vertex v1;
Vertex v2;
Vertex v3;
Vertex v4;
// interpolation helper
struct PlaneStepper3
{
float ddx, ddy;
float c;
void Setup(float v1_a, float v2_a, float v3_a)
{
float Aa = ((v3_a - v1_a) * (v2.y - v1.y) - (v2_a - v1_a) * (v3.y - v1.y));
float Ba = ((v3.x - v1.x) * (v2_a - v1_a) - (v2.x - v1.x) * (v3_a - v1_a));
float C = ((v2.x - v1.x) * (v3.y - v1.y) - (v3.x - v1.x) * (v2.y - v1.y));
ddx = -Aa / C;
ddy = -Ba / C;
c = (v1_a - ddx * v1.x - ddy * v1.y);
}
float Ip(float x, float y) const
{
return x * ddx + y * ddy + c;
}
float Ip(float x, float y, float W) const
{
return Ip(x, y) * W;
}
};
////// more interpolation helpers /////
// color helper
#define SEL_COL(col, i) ( ((col) >> (8 * i)) & 255 )
struct IPs3
{
PlaneStepper3 U;
PlaneStepper3 V;
PlaneStepper3 Col[4];
PlaneStepper3 Ofs[4];
void Setup(u8 TexU, u8 TexV, bool pp_Gourand)
{
u32 w = 8 << TexU, h = 8 << TexV;
U.Setup(v1.u * w * v1.z, v2.u * w * v2.z, v3.u * w * v3.z);
V.Setup(v1.v * h * v1.z, v2.v * h * v2.z, v3.v * h * v3.z);
if (pp_Gourand) {
for (int i = 0; i < 4; i++)
Col[i].Setup(SEL_COL(v1.col, i) * v1.z, SEL_COL(v2.col, i) * v2.z, SEL_COL(v3.col, i) * v3.z);
for (int i = 0; i < 4; i++)
Ofs[i].Setup(SEL_COL(v1.spc, i) * v1.z, SEL_COL(v2.spc, i) * v2.z, SEL_COL(v3.spc, i) * v3.z);
} else {
for (int i = 0; i < 4; i++)
Col[i].Setup(SEL_COL(v3.col, i) * v1.z, SEL_COL(v3.col, i) * v2.z, SEL_COL(v3.col, i) * v3.z);
for (int i = 0; i < 4; i++)
Ofs[i].Setup(SEL_COL(v3.spc, i) * v1.z, SEL_COL(v3.spc, i) * v2.z, SEL_COL(v3.spc, i) * v3.z);
}
}
};
struct DrawParameters
{
ISP_TSP isp;
struct TSP tsp;
struct TCW tcw;
struct TSP tsp2;
struct TSP tcw2;
};
struct FpuEntry {
IPs3 IPs;
DrawParameters params;
};
//
typedef u16 parameter_tag_t;
////// DEFINES ///////
#define MAX_RENDER_WIDTH 32
#define MAX_RENDER_HEIGHT 32
#define MAX_RENDER_PIXELS (MAX_RENDER_WIDTH * MAX_RENDER_HEIGHT)
#define STRIDE_PIXEL_OFFSET MAX_RENDER_WIDTH
#define PARAM_BUFFER_PIXEL_OFFSET 0
#define DEPTH1_BUFFER_PIXEL_OFFSET (MAX_RENDER_PIXELS*1)
#define DEPTH2_BUFFER_PIXEL_OFFSET (MAX_RENDER_PIXELS*2)
#define STENCIL_BUFFER_PIXEL_OFFSET (MAX_RENDER_PIXELS*3)
#define ACCUM1_BUFFER_PIXEL_OFFSET (MAX_RENDER_PIXELS*4)
#define ACCUM2_BUFFER_PIXEL_OFFSET (MAX_RENDER_PIXELS*5)
#define TAG_INVALID 1
///// GLOBAL STATE /////
// Render buffers
u16 ParamBuffer[MAX_RENDER_PIXELS];
f32 DepthBuffer1[MAX_RENDER_PIXELS];
f32 DepthBuffer2[MAX_RENDER_PIXELS];
u8 StencilBuffer[MAX_RENDER_PIXELS];
u32 AccumBuffer1[MAX_RENDER_PIXELS];
u32 AccumBuffer2[MAX_RENDER_PIXELS];
u16 CurrentPixel;
// Tile render state
u32 TileX;
u32 TileY;
// ISP/TSP render state
RenderMode render_mode;
parameter_tag_t CurrentTag;
FpuEntry CurrentFpuEntry;
// FPU render state
FpuEntry FpuEntries[1 * 1024];
u16 LastFpuEntry;
////// Rendering Helpers //////
static float mmin(float a, float b, float c, float d)
{
float rv = min(a, b);
rv = min(c, rv);
return max(d, rv);
}
static float mmax(float a, float b, float c, float d)
{
float rv = max(a, b);
rv = max(c, rv);
return min(d, rv);
}
////// TSP //////
u32 ColorCombiner(bool pp_Texture, bool pp_Offset, u32 pp_ShadInstr, u32 base, u32 textel, u32 offset) {
u32 rv = base;
if (pp_Texture)
{
if (pp_ShadInstr == 0)
{
//color.rgb = texcol.rgb;
//color.a = texcol.a;
rv = textel;
}
else if (pp_ShadInstr == 1)
{
//color.rgb *= texcol.rgb;
//color.a = texcol.a;
for (int i = 0; i < 3; i++)
{
rv |= (SEL_COL(textel, i) * SEL_COL(base, i) / 256) << (i * 8);
}
rv |= SEL_COL(textel, 3) << 24;
}
else if (pp_ShadInstr == 2)
{
//color.rgb=mix(color.rgb,texcol.rgb,texcol.a);
u8 tb = SEL_COL(textel, 3);
u8 cb = 255 - tb;
for (int i = 0; i < 3; i++)
{
rv |= ((SEL_COL(textel, i) * tb + SEL_COL(base, i) * cb) / 256) << (i * 8);
}
rv |= SEL_COL(base, 3) << 24;
}
else if (pp_ShadInstr == 3)
{
//color*=texcol
for (int i = 0; i < 4; i++)
{
rv |= (SEL_COL(textel, i) * SEL_COL(base, i) / 256) << (i * 8);
}
}
if (pp_Offset) {
// mix only color, saturate
for (int i = 0; i < 3; i++)
{
rv |= (SEL_COL(rv, i) * SEL_COL(offset, i) / 256) << (i * 8);
}
}
}
return rv;
}
static u32 InterpolateBase(bool pp_CheapShadows, bool pp_UseAlpha, const PlaneStepper3* Col, float x, float y, float W, u32 stencil) {
u32 rv = 0;
u32 mult = 256;
if (pp_CheapShadows) {
if (stencil & 1) {
mult = 128;
}
}
rv |= u8(Col[2].Ip(x, y, W) * mult / 256) << 0; // FIXME: why is input in RGBA instead of BGRA here?
rv |= u8(Col[1].Ip(x, y, W) * mult / 256) << 8;
rv |= u8(Col[0].Ip(x, y, W) * mult / 256) << 16;
rv |= u8(Col[3].Ip(x, y, W) * mult / 256) << 24;
if (!pp_UseAlpha)
{
rv |= 255 << 24;
}
//rv = 0xFFFFFFFF;
return rv;
}
static u32 BlendCoefs(u32 pp_AlphaInst, bool srcOther, u32 src, u32 dst) {
u32 rv;
switch(pp_AlphaInst>>1) {
// zero
case 0: rv = 0; break;
// other color
case 1: rv = srcOther? src : dst; break;
// src alpha
case 2: for (int i = 0; i < 4; i++) rv |= SEL_COL(src, 3) << (i * 8); break;
// dst alpha
case 3: for (int i = 0; i < 4; i++) rv |= SEL_COL(dst, 3) << (i * 8); break;
}
if (pp_AlphaInst & 1) {
rv = rv ^ 0xFFffFFff;
}
return rv;
}
static bool BlendingUnit(bool pp_AlphaTest, u32 pp_SrcSel, u32 pp_DstSel, u32 pp_SrcInst, u32 pp_DstInst, u32 col)
{
u32 rv = 0;
u32 src = pp_SrcSel ? AccumBuffer2[CurrentPixel] : col;
u32 dst = pp_DstSel ? AccumBuffer2[CurrentPixel] : AccumBuffer1[CurrentPixel];
u32 src_blend = BlendCoefs(pp_SrcInst, false, src, dst);
u32 dst_blend = BlendCoefs(pp_DstInst, true, src, dst);
for (int j = 0; j < 4; j++)
{
rv |= ((SEL_COL(src, j) * SEL_COL(src_blend, j) + SEL_COL(dst, j) * SEL_COL(dst_blend, j)) >> 8) << (j * 8);
}
if (!pp_AlphaTest || SEL_COL(src, 3) >= 128)
{
if (pp_DstSel)
AccumBuffer2[CurrentPixel] = rv;
else
AccumBuffer1[CurrentPixel] = rv;
return true;
}
else
{
return false;
}
}
static bool PixelFlush_tsp(float x, float y, float invW)
{
float W = 1 / invW;
parameter_tag_t* pb = &ParamBuffer[CurrentPixel];
u8* stencil = &StencilBuffer[CurrentPixel];
*pb |= TAG_INVALID;
u32 base = 0, textel = 0, offs = 0;
base = InterpolateBase(false, CurrentFpuEntry.params.tsp.UseAlpha, CurrentFpuEntry.IPs.Col, x, y, W, *stencil);
if (CurrentFpuEntry.params.isp.Texture) {
float u = CurrentFpuEntry.IPs.U.Ip(x, y, W);
float v = CurrentFpuEntry.IPs.V.Ip(x, y, W);
textel = 0xFFFFFFFF;//u * v * 65535*65535;//entry->textureFetch(&entry->texture, u, v);
if (CurrentFpuEntry.params.isp.Offset) {
offs = InterpolateBase(false, CurrentFpuEntry.params.tsp.UseAlpha, CurrentFpuEntry.IPs.Ofs, x, y, W, *stencil);
}
}
u32 col = ColorCombiner(CurrentFpuEntry.params.isp.Texture, CurrentFpuEntry.params.isp.Offset, CurrentFpuEntry.params.tsp.ShadInstr, base, textel, offs);
//col = FogUnit<pp_Offset, pp_ColorClamp, pp_FogCtrl>(col, 1/W, offs.a);
return BlendingUnit(render_mode == RM_PUNCHTHROUGH, CurrentFpuEntry.params.tsp.SrcSelect, CurrentFpuEntry.params.tsp.DstSelect, CurrentFpuEntry.params.tsp.SrcInstr, CurrentFpuEntry.params.tsp.DstInstr, col);
//return entry->blendingUnit(cb, col);
//*cb = col;
}
////// ISP //////
static void PixelFlush_isp(RenderMode render_mode, u32 depth_mode, float x, float y, float invW)
{
parameter_tag_t* pb = &ParamBuffer[CurrentPixel];
f32* zb = &DepthBuffer1[CurrentPixel];
f32* zb2 = &DepthBuffer2[CurrentPixel];
u8* stencil = &StencilBuffer[CurrentPixel];
u32 mode = depth_mode;
if (render_mode == RM_PUNCHTHROUGH)
mode = 6; // TODO: FIXME
else if (render_mode == RM_TRANSLUCENT)
mode = 3; // TODO: FIXME
else if (render_mode == RM_MODIFIER)
mode = 6;
/*
switch(mode) {
// never
case 0: return; break;
// less
case 1: if (invW >= *zb) return; break;
// equal
case 2: if (invW != *zb) return; break;
// less or equal
case 3: if (invW > *zb) return; break;
// greater
case 4: if (invW <= *zb) return; break;
// not equal
case 5: if (invW == *zb) return; break;
// greater or equal
case 6: if (invW < *zb) return; break;
// always
case 7: break;
}*/
switch (render_mode)
{
// OPAQ
case RM_OPAQUE:
{
// Z pre-pass only
*zb = invW;
*pb = CurrentTag;
}
break;
case RM_MODIFIER:
{
// Flip on Z pass
*stencil ^= 0b10;
}
break;
// PT
case RM_PUNCHTHROUGH:
{
// Z + TSP synchronized for alpha test
//if (AlphaTest_tsp(backend, x, y, pb, invW, tag))
{
*zb = invW;
*pb = CurrentTag;
}
}
break;
// Layer Peeling. zb2 holds the reference depth, zb is used to find closest to reference
case RM_TRANSLUCENT:
{
if (invW < *zb2)
return;
if (invW == *zb || invW == *zb2) {
parameter_tag_t tagExisting = *pb;
if (tagExisting & TAG_INVALID)
{
if (CurrentTag< tagExisting)
return;
}
else
{
if (CurrentTag >= tagExisting)
return;
}
}
//backend->PixelsDrawn++;
*zb = invW;
*pb = CurrentTag;
}
break;
}
}
u32 TileCommand(u32 command, u32 data) {
u8 op = command >> 24;
if (op == VTX) {
u8 vtx = (command >> 16) & 0xFF;
u8 idx = (command >> 8) & 0xFF;
Vertex* v = vtx == 0 ? &v1 : (vtx == 1 ? &v2 : (vtx == 2 ? &v3 : &v4));
switch (idx) {
case 0: v->x = (float&)data; break;
case 1: v->y = (float&)data; break;
case 2: v->z = (float&)data; break;
case 3: v->col = data; break;
case 4: v->spc = data; break;
case 5: v->u = (float&)data; break;
case 6: v->v = (float&)data; break;
case 7: v->col1 = data; break;
case 8: v->spc1 = data; break;
case 9: v->u1 = (float&)data; break;
case 10: v->v1 = (float&)data; break;
}
return 1;
} else if (op == DRAW) {
//Plane equation
#define FLUSH_NAN(a) isnan(a) ? 0 : a
const float Y1 = FLUSH_NAN(v1.y);
const float Y2 = FLUSH_NAN(v2.y);
const float Y3 = FLUSH_NAN(v3.y);
const float X1 = FLUSH_NAN(v1.x);
const float X2 = FLUSH_NAN(v2.x);
const float X3 = FLUSH_NAN(v3.x);
int sgn = 1;
// cull
{
//area: (X1-X3)*(Y2-Y3)-(Y1-Y3)*(X2-X3)
float area = ((X1 - X3) * (Y2 - Y3) - (Y1 - Y3) * (X2 - X3));
if (area > 0)
sgn = -1;
if (1 != 0) {
float abs_area = fabsf(area);
if (abs_area < 0.001f)
return 0;
}
}
// Bounding rectangle
int minx = mmin(X1, X2, X3, area_left);
int miny = mmin(Y1, Y2, Y3, area_top);
int spanx = mmax(X1+1, X2+1, X3+1, area_right) - minx + 1;
int spany = mmax(Y1+1, Y2+1, Y3+1, area_bottom) - miny + 1;
//Inside scissor area?
if (spanx < 0 || spany < 0)
return 0;
// Half-edge constants
const float DX12 = sgn * (X1 - X2);
const float DX23 = sgn * (X2 - X3);
const float DX31 = sgn * (X3 - X1);
const float DX41 = 0;
const float DY12 = sgn * (Y1 - Y2);
const float DY23 = sgn * (Y2 - Y3);
const float DY31 = sgn * (Y3 - Y1);
const float DY41 = 0;
float C1 = DY12 * X1 - DX12 * Y1;
float C2 = DY23 * X2 - DX23 * Y2;
float C3 = DY31 * X3 - DX31 * Y3;
float C4 = 1;
u16 CurrentPixelY = (miny - area_top) * STRIDE_PIXEL_OFFSET + (minx - area_left);
PlaneStepper3 Z;
Z.Setup(v1.z, v2.z, v3.z);
CurrentFpuEntry.IPs.Setup(CurrentFpuEntry.params.tsp.TexU, CurrentFpuEntry.params.tsp.TexV, CurrentFpuEntry.params.isp.Gouraud);
FpuEntries[LastFpuEntry] = CurrentFpuEntry;
CurrentTag = LastFpuEntry << 1;
LastFpuEntry += 1;
float halfpixel = 0.5f;
float y_ps = miny + halfpixel;
float minx_ps = minx + halfpixel;
///auto pixelFlush = pixelPipeline->GetIsp(render_mode, params->isp);
// Loop through pixels
for (int y = spany; y > 0; y -= 1)
{
CurrentPixel = CurrentPixelY;
float x_ps = minx_ps;
for (int x = spanx; x > 0; x -= 1)
{
float Xhs12 = C1 + DX12 * y_ps - DY12 * x_ps;
float Xhs23 = C2 + DX23 * y_ps - DY23 * x_ps;
float Xhs31 = C3 + DX31 * y_ps - DY31 * x_ps;
float Xhs41 = C4 + DX41 * y_ps - DY41 * x_ps;
bool inTriangle = Xhs12 >= 0 && Xhs23 >= 0 && Xhs31 >= 0 && Xhs41 >= 0;
if (inTriangle)
{
float invW = Z.Ip(x_ps, y_ps);
PixelFlush_isp(render_mode, CurrentFpuEntry.params.isp.DepthMode, x_ps, y_ps, invW);
}
CurrentPixel++;
x_ps = x_ps + 1;
}
next_y:
CurrentPixelY += STRIDE_PIXEL_OFFSET;
y_ps = y_ps + 1;
}
return 1;
} else if (op == READ) {
u8 buffer = (command >> 16) & 0xFF;
u16 index = command & 1023;
if (buffer == 0)
return ParamBuffer[index];
else if (buffer == 1)
return DepthBuffer1[index];
else if (buffer == 2)
return DepthBuffer2[index];
else if (buffer == 3)
return StencilBuffer[index];
else if (buffer == 4)
return AccumBuffer1[index];
else if (buffer == 5)
return AccumBuffer2[index];
} else if (op == ISP) {
(u32&)CurrentFpuEntry.params.isp = data;
} else if (op == TSP) {
(u32&)CurrentFpuEntry.params.tsp = data;
} else if (op == TCW) {
(u32&)CurrentFpuEntry.params.tcw= data;
} else if (op == RENDERMODE) {
render_mode = (RenderMode)data;
} else if (op == TAG) {
CurrentTag = data;
} else if (op == CLEAR) {
memset(ParamBuffer, 0, sizeof(ParamBuffer));
memset(DepthBuffer1, 0, sizeof(DepthBuffer1));
memset(DepthBuffer2, 0, sizeof(DepthBuffer2));
memset(StencilBuffer, 0, sizeof(StencilBuffer));
memset(AccumBuffer1, 0, sizeof(AccumBuffer1));
memset(AccumBuffer2, 0, sizeof(AccumBuffer2));
} else if (op == DRAWTSP) {
float halfpixel = 0.5f;
for (int y = 0; y < 32; y++) {
for (int x = 0; x < 32; x++) {
CurrentPixel = (y << 5) | x;
parameter_tag_t tag = ParamBuffer[CurrentPixel];
if (!(tag & TAG_INVALID)) {
if (CurrentTag != tag) {
CurrentTag = tag;
CurrentFpuEntry = FpuEntries[tag >> 1];
}
if (CurrentTag != 0)
PixelFlush_tsp(TileX + x + halfpixel, TileY + y + halfpixel, DepthBuffer1[CurrentPixel]);
}
}
}
} else if (op == TILEX) {
TileX = data;
} else if (op == TILEY) {
TileY = data;
} else if (op == CLEARFPU) {
LastFpuEntry = 1;
} else if (op == AREA) {
u8 item = (command >> 16) & 0xFF;
if (item == 0) {
area_left = data;
} else if (item == 1) {
area_top = data;
} else if (item == 2) {
area_right = data;
} else if (item == 3) {
area_bottom = data;
}
}
return 0;
}
#pragma once
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef float f32;
enum TileCommands {
VTX,
ISP,
TSP,
TCW,
RENDERMODE,
TAG,
DRAW,
READ,
CLEAR,
DRAWTSP,
TILEX,
TILEY,
CLEARFPU,
AREA,
};
u32 TileCommand(u32 command, u32 data);
/*
glue logic to connect the hls c code with refsw
*/
#include "refrend_base.h"
#include "hw/pvr/Renderer_if.h"
#include "refrend_hls.h"
static u32 pixels[1024];
static u32 debug_pixels[1024 * 6];
struct HlsPixelPipeline : RefRendInterface {
// backend specific init
virtual bool Init() {
return true;
}
// Clear the buffers
virtual void ClearBuffers(u32 paramValue, float depthValue, u32 stencilValue) {
TileCommand(CLEAR << 24, 0);
}
// Clear only the param buffer (used for peeling)
virtual void ClearParamBuffer(u32 paramValue) {
}
// Clear and set DEPTH2 for peeling
virtual void PeelBuffers(float depthValue, u32 stencilValue) {
}
// Summarize tile after rendering modvol (inside)
virtual void SummarizeStencilOr() {
}
// Summarize tile after rendering modvol (outside)
virtual void SummarizeStencilAnd() {
}
// Clear the pixel drawn counter
virtual void ClearPixelsDrawn() {
}
// Get the pixel drawn counter. Used during layer peeling to determine when to stop processing
virtual u32 GetPixelsDrawn() {
return 0;
}
// Add an entry to the fpu parameters list
virtual parameter_tag_t AddFpuEntry(DrawParameters* params, Vertex* vtx, RenderMode render_mode, ISP_BACKGND_T_type core_tag) {
return 0;
}
// Clear the fpu parameters list
virtual void ClearFpuEntries() {
TileCommand(CLEARFPU << 24, 0);
}
// Get the final output of the 32x32 tile. Used to write to the VRAM framebuffer
virtual u8* GetColorOutputBuffer() {
for (int i = 0; i < 1024; i++) {
pixels[i] = TileCommand((READ << 24) | ( 4 << 16) | (i), 0);
}
return (u8*)pixels;
}
// Render to ACCUM from TAG buffer
// TAG holds references to triangles, ACCUM is the tile framebuffer
virtual void RenderParamTags(RenderMode rm, int tileX, int tileY) {
TileCommand(TILEX << 24, tileX);
TileCommand(TILEY << 24, tileY);
TileCommand(DRAWTSP << 24, 0);
}
// RasterizeTriangle
virtual void RasterizeTriangle(RenderMode render_mode, DrawParameters* params, parameter_tag_t tag, int vertex_offset, const Vertex& v1, const Vertex& v2, const Vertex& v3, const Vertex* v4, taRECT* area) {
TileCommand((AREA << 24) | (0 << 16), area->left);
TileCommand((AREA << 24) | (1 << 16), area->top);
TileCommand((AREA << 24) | (2 << 16), area->right - 1);
TileCommand((AREA << 24) | (3 << 16), area->bottom - 1);
for (int vtx = 0; vtx < 3; vtx++) {
const Vertex* v = vtx == 0 ? &v1 : (vtx == 1 ? &v2 : (vtx == 2 ? &v3 : v4));
TileCommand((VTX << 24) | ( vtx << 16) | ( 0 << 8), (u32&)v->x);
TileCommand((VTX << 24) | ( vtx << 16) | ( 1 << 8), (u32&)v->y);
TileCommand((VTX << 24) | ( vtx << 16) | ( 2 << 8), (u32&)v->z);
TileCommand((VTX << 24) | ( vtx << 16) | ( 3 << 8), *(u32*)v->col);
TileCommand((VTX << 24) | ( vtx << 16) | ( 4 << 8), *(u32*)v->spc);
TileCommand((VTX << 24) | ( vtx << 16) | ( 5 << 8), (u32&)v->u);
TileCommand((VTX << 24) | ( vtx << 16) | ( 6 << 8), (u32&)v->v);
}
TileCommand(ISP << 24, params->isp.full);
TileCommand(TSP << 24, params->tsp.full);
TileCommand(TCW << 24, params->tcw.full);
TileCommand(RENDERMODE << 24, 0);
TileCommand(DRAW << 24, 0);
}
// Debug-level
virtual u8* DebugGetAllBuffers() {
for (int j = 0 ; j < 6; j++) {
for (int i = 0; i < 1024; i++) {
debug_pixels[j * 1024 + i] = TileCommand((READ << 24) | ( j << 16) | (i), 0);
}
}
return (u8*)debug_pixels;
}
};
#if FEAT_TA == TA_LLE
Renderer* rend_refhls(u8* vram) {
return rend_refred_base(vram, [=]() {
return (RefRendInterface*) new HlsPixelPipeline();
});
}
static auto refrend = RegisterRendererBackend(rendererbackend_t{ "refhls-sim", "refhls-sim", 0, rend_refhls });
Renderer* rend_refhls_debug(u8* vram) {
return rend_refred_base(vram, [=]() {
return rend_refred_debug((RefRendInterface*) new HlsPixelPipeline());
});
}
static auto refrend_debug = RegisterRendererBackend(rendererbackend_t{ "refhls-sim-dbg", "refhls-sim-dbg", 0, rend_refhls_debug });
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment