Last active
March 12, 2021 14:33
-
-
Save skmp/fc3ae9b26f88b37706642cc23b49adca to your computer and use it in GitHub Desktop.
FPGAdc: Getting started w/ HLS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************* | |
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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