gpu_line.cpp 6.46 KB
Newer Older
Libretro-Admin's avatar
Libretro-Admin committed
1
#ifdef __cplusplus
Libretro-Admin's avatar
Update    
Libretro-Admin committed
2
3

#ifndef __STDC_CONSTANT_MACROS
Libretro-Admin's avatar
Libretro-Admin committed
4
#define __STDC_CONSTANT_MACROS
Libretro-Admin's avatar
Update    
Libretro-Admin committed
5
6
#endif

Libretro-Admin's avatar
Libretro-Admin committed
7
8
9
#ifdef _STDINT_H
#undef _STDINT_H
#endif
Libretro-Admin's avatar
Update    
Libretro-Admin committed
10

Libretro-Admin's avatar
Libretro-Admin committed
11
12
13
# include <stdint.h>
#endif

Themaister's avatar
Themaister committed
14
15
struct line_fxp_coord
{
Libretro-Admin's avatar
Libretro-Admin committed
16
17
   uint64_t x, y;
   uint32_t r, g, b;
Themaister's avatar
Themaister committed
18
19
20
21
};

struct line_fxp_step
{
Libretro-Admin's avatar
Libretro-Admin committed
22
23
   int64_t dx_dk, dy_dk;
   int32_t dr_dk, dg_dk, db_dk;
Themaister's avatar
Themaister committed
24
25
};

Libretro-Admin's avatar
Libretro-Admin committed
26
27
#define LINE_XY_FRACTBITS  32
#define LINE_RGB_FRACTBITS 12
Themaister's avatar
Themaister committed
28

Libretro-Admin's avatar
Libretro-Admin committed
29
template<bool gouraud>
30
31
static INLINE void line_point_to_fixed_point_coord(const line_point *point,
      const line_fxp_step *step, line_fxp_coord *coord)
Themaister's avatar
Themaister committed
32
{
Libretro-Admin's avatar
Libretro-Admin committed
33
34
   coord->x  = ((uint64_t)point->x << LINE_XY_FRACTBITS) | (UINT64_C(1) << (LINE_XY_FRACTBITS - 1));
   coord->y  = ((uint64_t)point->y << LINE_XY_FRACTBITS) | (UINT64_C(1) << (LINE_XY_FRACTBITS - 1));
Themaister's avatar
Themaister committed
35

36
   coord->x -= 1024;
Libretro-Admin's avatar
Libretro-Admin committed
37

38
39
   if(step->dy_dk < 0)
      coord->y -= 1024;
Libretro-Admin's avatar
Libretro-Admin committed
40

Libretro-Admin's avatar
Libretro-Admin committed
41
   if(gouraud)
Libretro-Admin's avatar
Libretro-Admin committed
42
   {
Libretro-Admin's avatar
Libretro-Admin committed
43
44
45
      coord->r = (point->r << LINE_RGB_FRACTBITS) | (1 << (LINE_RGB_FRACTBITS - 1));
      coord->g = (point->g << LINE_RGB_FRACTBITS) | (1 << (LINE_RGB_FRACTBITS - 1));
      coord->b = (point->b << LINE_RGB_FRACTBITS) | (1 << (LINE_RGB_FRACTBITS - 1));
Libretro-Admin's avatar
Libretro-Admin committed
46
   }
Themaister's avatar
Themaister committed
47
48
}

49
static INLINE int64_t line_divide(int64_t delta, int32_t dk)
Themaister's avatar
Themaister committed
50
{
Libretro-Admin's avatar
Libretro-Admin committed
51
52
   delta = (uint64_t)delta << LINE_XY_FRACTBITS;

Libretro-Admin's avatar
Libretro-Admin committed
53
54
55
56
   if(delta < 0)
      delta -= dk - 1;
   if(delta > 0)
      delta += dk - 1;
Themaister's avatar
Themaister committed
57

Libretro-Admin's avatar
Libretro-Admin committed
58
   return(delta / dk);
Themaister's avatar
Themaister committed
59
60
}

Libretro-Admin's avatar
Libretro-Admin committed
61
template<bool gouraud>
62
63
static INLINE void line_points_to_fixed_point_step(const line_point *point0,
      const line_point *point1, const int32_t dk, line_fxp_step *step)
Themaister's avatar
Themaister committed
64
{
Libretro-Admin's avatar
Libretro-Admin committed
65
66
   if(!dk)
   {
67
68
      step->dx_dk = 0;
      step->dy_dk = 0;
Libretro-Admin's avatar
Libretro-Admin committed
69

Libretro-Admin's avatar
Libretro-Admin committed
70
      if(gouraud)
Libretro-Admin's avatar
Libretro-Admin committed
71
      {
72
73
74
         step->dr_dk = 0;
         step->dg_dk = 0;
         step->db_dk = 0;
Libretro-Admin's avatar
Libretro-Admin committed
75
76
77
78
      }
      return;
   }

Libretro-Admin's avatar
Libretro-Admin committed
79
80
   step->dx_dk = line_divide(point1->x - point0->x, dk);
   step->dy_dk = line_divide(point1->y - point0->y, dk);
Libretro-Admin's avatar
Libretro-Admin committed
81

Libretro-Admin's avatar
Libretro-Admin committed
82
   if(gouraud)
Libretro-Admin's avatar
Libretro-Admin committed
83
   {
Libretro-Admin's avatar
Libretro-Admin committed
84
85
86
      step->dr_dk = (int32_t)((uint32_t)(point1->r - point0->r) << LINE_RGB_FRACTBITS) / dk;
      step->dg_dk = (int32_t)((uint32_t)(point1->g - point0->g) << LINE_RGB_FRACTBITS) / dk;
      step->db_dk = (int32_t)((uint32_t)(point1->b - point0->b) << LINE_RGB_FRACTBITS) / dk;
Libretro-Admin's avatar
Libretro-Admin committed
87
   }
Themaister's avatar
Themaister committed
88
89
}

Libretro-Admin's avatar
Libretro-Admin committed
90
template<bool gouraud>
91
static INLINE void AddLineStep(line_fxp_coord *point, const line_fxp_step *step)
Themaister's avatar
Themaister committed
92
{
93
94
   point->x += step->dx_dk;
   point->y += step->dy_dk;
Libretro-Admin's avatar
Libretro-Admin committed
95

Libretro-Admin's avatar
Libretro-Admin committed
96
   if(gouraud)
Libretro-Admin's avatar
Libretro-Admin committed
97
   {
98
99
100
      point->r += step->dr_dk;
      point->g += step->dg_dk;
      point->b += step->db_dk;
Libretro-Admin's avatar
Libretro-Admin committed
101
   }
Themaister's avatar
Themaister committed
102
103
}

104
105
template<bool gouraud, int BlendMode>
static void DrawLine(PS_GPU *gpu, line_point *points, bool MaskEval_TA)
Themaister's avatar
Themaister committed
106
{
Libretro-Admin's avatar
Libretro-Admin committed
107
108
   line_fxp_coord cur_point;
   line_fxp_step step;
Libretro-Admin's avatar
Libretro-Admin committed
109
110
111
   int32_t delta_x = abs(points[1].x - points[0].x);
   int32_t delta_y = abs(points[1].y - points[0].y);
   int32_t k       = (delta_x > delta_y) ? delta_x : delta_y;
Libretro-Admin's avatar
Libretro-Admin committed
112
113

   if(points[0].x > points[1].x && k)
Libretro-Admin's avatar
Libretro-Admin committed
114
      vertex_swap(line_point, points[1], points[0]);
Libretro-Admin's avatar
Libretro-Admin committed
115

Libretro-Admin's avatar
Libretro-Admin committed
116
   gpu->DrawTimeAvail -= k * 2;
Libretro-Admin's avatar
Libretro-Admin committed
117

Libretro-Admin's avatar
Libretro-Admin committed
118
119
   line_points_to_fixed_point_step<gouraud>(&points[0], &points[1], k, &step);
   line_point_to_fixed_point_coord<gouraud>(&points[0], &step, &cur_point);
Libretro-Admin's avatar
Libretro-Admin committed
120

rz5's avatar
rz5 committed
121
   for(int32_t i = 0; i <= k; i++)  // <= is not a typo.
Themaister's avatar
Themaister committed
122
   {
Libretro-Admin's avatar
Libretro-Admin committed
123
124
125
      // Sign extension is not necessary here for x and y, due to the maximum values that ClipX1 and ClipY1 can contain.
      int32_t x = (cur_point.x >> LINE_XY_FRACTBITS) & 2047;
      int32_t y = (cur_point.y >> LINE_XY_FRACTBITS) & 2047;
Libretro-Admin's avatar
Libretro-Admin committed
126

Libretro-Admin's avatar
Libretro-Admin committed
127
      if(!LineSkipTest(gpu, y))
Libretro-Admin's avatar
Libretro-Admin committed
128
129
      {
         uint8_t r, g, b;
Libretro-Admin's avatar
Libretro-Admin committed
130
         uint16_t pix = 0x8000;
Libretro-Admin's avatar
Libretro-Admin committed
131

Libretro-Admin's avatar
Libretro-Admin committed
132
         if(gouraud)
Libretro-Admin's avatar
Libretro-Admin committed
133
         {
Libretro-Admin's avatar
Libretro-Admin committed
134
135
136
            r = cur_point.r >> LINE_RGB_FRACTBITS;
            g = cur_point.g >> LINE_RGB_FRACTBITS;
            b = cur_point.b >> LINE_RGB_FRACTBITS;
Libretro-Admin's avatar
Libretro-Admin committed
137
138
139
140
141
142
143
144
         }
         else
         {
            r = points[0].r;
            g = points[0].g;
            b = points[0].b;
         }

Libretro-Admin's avatar
Libretro-Admin committed
145
         if(DitherEnabled(gpu))
Libretro-Admin's avatar
Libretro-Admin committed
146
         {
Libretro-Admin's avatar
Libretro-Admin committed
147
            uint8_t *dither_offset = gpu->DitherLUT[y & 3][x & 3];
Libretro-Admin's avatar
Libretro-Admin committed
148
149
            pix = 0x8000 | (dither_offset[r] << 0) | (dither_offset[g] << 5) | 
               (dither_offset[b] << 10);
Libretro-Admin's avatar
Libretro-Admin committed
150
151
152
         }
         else
         {
Libretro-Admin's avatar
Libretro-Admin committed
153
            pix = 0x8000 | ((r >> 3) << 0) | ((g >> 3) << 5) | ((b >> 3) << 10);
Libretro-Admin's avatar
Libretro-Admin committed
154
155
156
         }

         // FIXME: There has to be a faster way than checking for being inside the drawing area for each pixel.
Libretro-Admin's avatar
Libretro-Admin committed
157
         if(x >= gpu->ClipX0 && x <= gpu->ClipX1 && y >= gpu->ClipY0 && y <= gpu->ClipY1)
158
            PlotNativePixel<BlendMode, false>(gpu, x, y, pix, MaskEval_TA);
Libretro-Admin's avatar
Libretro-Admin committed
159
160
      }

Libretro-Admin's avatar
Libretro-Admin committed
161
      AddLineStep<gouraud>(&cur_point, &step);
Libretro-Admin's avatar
Libretro-Admin committed
162
163
164
   }
}

165
166
template<bool polyline, bool gouraud, int BlendMode>
static void Command_DrawLine(PS_GPU *gpu, const uint32_t *cb, bool MaskEval_TA)
Libretro-Admin's avatar
Libretro-Admin committed
167
168
{
   line_point points[2];
Libretro-Admin's avatar
Libretro-Admin committed
169
   const uint8_t cc = cb[0] >> 24; // For pline handling later.
Libretro-Admin's avatar
Libretro-Admin committed
170

rz5's avatar
rz5 committed
171
   gpu->DrawTimeAvail   -= 16;   // FIXME, correct time.
Libretro-Admin's avatar
Libretro-Admin committed
172

Libretro-Admin's avatar
Libretro-Admin committed
173
   if(polyline && gpu->InCmd == INCMD_PLINE)
Libretro-Admin's avatar
Libretro-Admin committed
174
175
   {
      //printf("PLINE N\n");
Libretro-Admin's avatar
Libretro-Admin committed
176
      points[0] = gpu->InPLine_PrevPoint;
Themaister's avatar
Themaister committed
177
178
179
   }
   else
   {
Libretro-Admin's avatar
Libretro-Admin committed
180
181
182
183
184
      points[0].r = (*cb >> 0) & 0xFF;
      points[0].g = (*cb >> 8) & 0xFF;
      points[0].b = (*cb >> 16) & 0xFF;
      cb++;

Libretro-Admin's avatar
Libretro-Admin committed
185
186
      points[0].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + gpu->OffsX;
      points[0].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + gpu->OffsY;
Libretro-Admin's avatar
Libretro-Admin committed
187
      cb++;
Themaister's avatar
Themaister committed
188
189
   }

Libretro-Admin's avatar
Libretro-Admin committed
190
   if(gouraud)
Themaister's avatar
Themaister committed
191
   {
Libretro-Admin's avatar
Libretro-Admin committed
192
193
194
195
      points[1].r = (*cb >> 0) & 0xFF;
      points[1].g = (*cb >> 8) & 0xFF;
      points[1].b = (*cb >> 16) & 0xFF;
      cb++;
Themaister's avatar
Themaister committed
196
197
198
   }
   else
   {
Libretro-Admin's avatar
Libretro-Admin committed
199
200
201
      points[1].r = points[0].r;
      points[1].g = points[0].g;
      points[1].b = points[0].b;
Themaister's avatar
Themaister committed
202
203
   }

Libretro-Admin's avatar
Libretro-Admin committed
204
205
   points[1].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + gpu->OffsX;
   points[1].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + gpu->OffsY;
Libretro-Admin's avatar
Libretro-Admin committed
206
   cb++;
Themaister's avatar
Themaister committed
207

Libretro-Admin's avatar
Libretro-Admin committed
208
209
   if(polyline)
   {
Libretro-Admin's avatar
Libretro-Admin committed
210
      gpu->InPLine_PrevPoint = points[1];
Themaister's avatar
Themaister committed
211

Libretro-Admin's avatar
Libretro-Admin committed
212
      if(gpu->InCmd != INCMD_PLINE)
Libretro-Admin's avatar
Libretro-Admin committed
213
      {
Libretro-Admin's avatar
Libretro-Admin committed
214
215
         gpu->InCmd = INCMD_PLINE;
         gpu->InCmd_CC = cc;
Libretro-Admin's avatar
Libretro-Admin committed
216
217
      }
   }
Themaister's avatar
Themaister committed
218

219
220
221
222
223
224
225
226
227
   int32_t delta_x = abs(points[1].x - points[0].x);
   int32_t delta_y = abs(points[1].y - points[0].y);

   if(delta_x >= 1024)
     return;

   if(delta_y >= 512)
     return;

Libretro-Admin's avatar
Libretro-Admin committed
228
229
230
231
232
233
234
235
236
237
238
239
240
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) || defined(HAVE_VULKAN)
   if (rsx_intf_is_type() == RSX_OPENGL || rsx_intf_is_type() == RSX_VULKAN)
   {
      rsx_intf_push_line(  points[0].x, points[0].y,
            points[1].x, points[1].y,
            ((uint32_t)points[0].r) | ((uint32_t)points[0].g << 8) | ((uint32_t)points[0].b << 16),
            ((uint32_t)points[1].r) | ((uint32_t)points[1].g << 8) | ((uint32_t)points[1].b << 16),
            DitherEnabled(gpu),
            BlendMode,
            MaskEval_TA,
            gpu->MaskSetOR);
   }
#endif
Libretro-Admin's avatar
Libretro-Admin committed
241

242
   if (rsx_intf_has_software_renderer())
243
      DrawLine<gouraud, BlendMode>(gpu, points, MaskEval_TA);
Libretro-Admin's avatar
Libretro-Admin committed
244
}