Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
lines.c
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2026 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27// Exhaustive line probes. Naming convention:
28// LS_<oct> flat shallow line in octant <oct> (1..8)
29// LT_<oct> flat steep line in octant <oct>
30// LR_<axis> reverse-direction (right-to-left or bottom-to-top)
31// LC_<dir> clipped at draw-area edge
32// LZ_<n> zero-length at position n
33// LG gouraud line
34// LP polyline 3-vertex
35// LST semi-trans line
36//
37// Octant numbering (standard):
38// 1: dx > 0, dy > 0, |dx| > |dy| (shallow down-right)
39// 2: dx > 0, dy > 0, |dy| > |dx| (steep down-right)
40// 3: dx < 0, dy > 0, |dy| > |dx| (steep down-left)
41// 4: dx < 0, dy > 0, |dx| > |dy| (shallow down-left)
42// 5: dx < 0, dy < 0, |dx| > |dy| (shallow up-left)
43// 6: dx < 0, dy < 0, |dy| > |dx| (steep up-left)
44// 7: dx > 0, dy < 0, |dy| > |dx| (steep up-right)
45// 8: dx > 0, dy < 0, |dx| > |dy| (shallow up-right)
46//
47// Phase-2 already covered octant 1 (lineShallow) and the D45/DN45 axis
48// boundaries. Phase-10 fills 2-8 plus polylines / gouraud / semi-trans.
49
50// clang-format off
51
53
54// Octant 2: steep down-right (dx>0, dy>0, dy > dx). (0,0) -> (3, 10).
55static void drawLS_oct2(void) {
56 rasterReset();
57 rasterClearTestRegion(0, 0, 16, 16);
58 rasterFlatLine(RASTER_CMD_RED, 0, 0, 3, 10);
59 rasterFlushPrimitive();
60}
61
62// Octant 3: steep down-left (dx<0, dy>0, dy > |dx|). (10,0) -> (7, 10).
63static void drawLS_oct3(void) {
64 rasterReset();
65 rasterClearTestRegion(0, 0, 16, 16);
66 rasterFlatLine(RASTER_CMD_GREEN, 10, 0, 7, 10);
67 rasterFlushPrimitive();
68}
69
70// Octant 4: shallow down-left. (10, 0) -> (0, 3).
71static void drawLS_oct4(void) {
72 rasterReset();
73 rasterClearTestRegion(0, 0, 16, 8);
74 rasterFlatLine(RASTER_CMD_BLUE, 10, 0, 0, 3);
75 rasterFlushPrimitive();
76}
77
78// Octant 5: shallow up-left. (10, 10) -> (0, 7).
79static void drawLS_oct5(void) {
80 rasterReset();
81 rasterClearTestRegion(0, 0, 16, 16);
82 rasterFlatLine(RASTER_CMD_WHITE, 10, 10, 0, 7);
83 rasterFlushPrimitive();
84}
85
86// Octant 6: steep up-left. (10, 10) -> (7, 0).
87static void drawLS_oct6(void) {
88 rasterReset();
89 rasterClearTestRegion(0, 0, 16, 16);
90 rasterFlatLine(RASTER_CMD_RED, 10, 10, 7, 0);
91 rasterFlushPrimitive();
92}
93
94// Octant 7: steep up-right. (0, 10) -> (3, 0).
95static void drawLS_oct7(void) {
96 rasterReset();
97 rasterClearTestRegion(0, 0, 16, 16);
98 rasterFlatLine(RASTER_CMD_GREEN, 0, 10, 3, 0);
99 rasterFlushPrimitive();
100}
101
102// Octant 8: shallow up-right. (0, 3) -> (10, 0).
103static void drawLS_oct8(void) {
104 rasterReset();
105 rasterClearTestRegion(0, 0, 16, 8);
106 rasterFlatLine(RASTER_CMD_BLUE, 0, 3, 10, 0);
107 rasterFlushPrimitive();
108}
109
110// Reverse-direction horizontal: (10, 5) -> (5, 5).
111static void drawLR_horiz(void) {
112 rasterReset();
113 rasterClearTestRegion(0, 0, 16, 8);
114 rasterFlatLine(RASTER_CMD_RED, 10, 5, 5, 5);
115 rasterFlushPrimitive();
116}
117
118// Reverse-direction vertical: (5, 10) -> (5, 5).
119static void drawLR_vert(void) {
120 rasterReset();
121 rasterClearTestRegion(0, 0, 8, 16);
122 rasterFlatLine(RASTER_CMD_GREEN, 5, 10, 5, 5);
123 rasterFlushPrimitive();
124}
125
126// Clipped right: line extends past draw-area X (1024). Draw area is
127// the default 1024x512 - so clip at X=1023 implicitly. We narrow the
128// draw area to test clipping at a closer boundary.
129static void drawLC_right(void) {
130 rasterReset();
131 rasterClearTestRegion(0, 0, 24, 8);
132 setDrawingArea(0, 0, 12, 8); /* draw-X clipped at 12 (exclusive) */
133 rasterFlatLine(RASTER_CMD_WHITE, 0, 4, 20, 4);
134 rasterFlushPrimitive();
135 /* Restore default draw area for subsequent tests. */
138}
139
140// Clipped bottom: line extends past draw-area Y.
141static void drawLC_bottom(void) {
142 rasterReset();
143 rasterClearTestRegion(0, 0, 8, 24);
144 setDrawingArea(0, 0, 8, 12);
145 rasterFlatLine(RASTER_CMD_BLUE, 4, 0, 4, 20);
146 rasterFlushPrimitive();
149}
150
151// Zero-length lines at different positions.
152static void drawLZ_at(int16_t x, int16_t y) {
153 rasterReset();
154 rasterClearTestRegion(0, 0, 32, 16);
155 rasterFlatLine(RASTER_CMD_RED, x, y, x, y);
156 rasterFlushPrimitive();
157}
158
159// Gouraud line: red -> blue over 10 pixels horizontally.
160static void drawLG(void) {
161 rasterReset();
162 rasterClearTestRegion(0, 0, 16, 8);
163 rasterGouraudLine(RASTER_CMD_RED, 0, 5,
164 RASTER_CMD_BLUE, 10, 5);
165 rasterFlushPrimitive();
166}
167
168// Polyline 3-vertex: (0, 0) -> (5, 5) -> (10, 0). Two diagonal
169// segments meeting at the apex.
170static void drawLP(void) {
171 rasterReset();
172 rasterClearTestRegion(0, 0, 16, 16);
173 rasterFlatPolyline3(RASTER_CMD_GREEN,
174 0, 0,
175 5, 5,
176 10, 0);
177 rasterFlushPrimitive();
178}
179
180// Semi-trans line: GP0(0x42) over a red-filled background.
181static void drawLST(void) {
182 rasterReset();
183 rasterFillRect(0, 0, 16, 8, RASTER_VRAM_RED);
184 rasterFlatLineSemi(RASTER_CMD_GREEN, 0, 4, 10, 4);
185 rasterFlushPrimitive();
186}
187
188) // CESTER_BODY
189
190// ==========================================================================
191// Octant 2: steep down-right. (0, 0) -> (3, 10).
192// Hardware steps Y the longer axis; X advances every ~3.33 rows.
193// ==========================================================================
194
195CESTER_TEST(ls_oct2_start, gpu_raster_phase10,
196 drawLS_oct2();
198)
199CESTER_TEST(ls_oct2_mid_y5, gpu_raster_phase10,
200 drawLS_oct2();
201 /* At y=5, x ~ 0 + 5*(3/10) = 1.5 -> Bresenham picks 1 or 2. */
203)
204CESTER_TEST(ls_oct2_mid_y5_x2, gpu_raster_phase10,
205 drawLS_oct2();
207)
208CESTER_TEST(ls_oct2_end, gpu_raster_phase10,
209 drawLS_oct2();
211)
212
213// ==========================================================================
214// Octant 3: steep down-left. (10, 0) -> (7, 10).
215// ==========================================================================
216
217CESTER_TEST(ls_oct3_start, gpu_raster_phase10,
218 drawLS_oct3();
220)
221CESTER_TEST(ls_oct3_mid, gpu_raster_phase10,
222 drawLS_oct3();
224)
225CESTER_TEST(ls_oct3_end, gpu_raster_phase10,
226 drawLS_oct3();
228)
229
230// ==========================================================================
231// Octant 4: shallow down-left. (10, 0) -> (0, 3).
232// ==========================================================================
233
234CESTER_TEST(ls_oct4_start, gpu_raster_phase10,
235 drawLS_oct4();
237)
238CESTER_TEST(ls_oct4_mid, gpu_raster_phase10,
239 drawLS_oct4();
241)
242CESTER_TEST(ls_oct4_end, gpu_raster_phase10,
243 drawLS_oct4();
245)
246
247// ==========================================================================
248// Octant 5: shallow up-left. (10, 10) -> (0, 7).
249// ==========================================================================
250
251CESTER_TEST(ls_oct5_start, gpu_raster_phase10,
252 drawLS_oct5();
254)
255CESTER_TEST(ls_oct5_mid, gpu_raster_phase10,
256 drawLS_oct5();
258)
259CESTER_TEST(ls_oct5_end, gpu_raster_phase10,
260 drawLS_oct5();
262)
263
264// ==========================================================================
265// Octant 6: steep up-left. (10, 10) -> (7, 0).
266// ==========================================================================
267
268CESTER_TEST(ls_oct6_start, gpu_raster_phase10,
269 drawLS_oct6();
271)
272CESTER_TEST(ls_oct6_mid, gpu_raster_phase10,
273 drawLS_oct6();
275)
276CESTER_TEST(ls_oct6_end, gpu_raster_phase10,
277 drawLS_oct6();
279)
280
281// ==========================================================================
282// Octant 7: steep up-right. (0, 10) -> (3, 0).
283// ==========================================================================
284
285CESTER_TEST(ls_oct7_start, gpu_raster_phase10,
286 drawLS_oct7();
288)
289CESTER_TEST(ls_oct7_mid, gpu_raster_phase10,
290 drawLS_oct7();
292)
293CESTER_TEST(ls_oct7_end, gpu_raster_phase10,
294 drawLS_oct7();
296)
297
298// ==========================================================================
299// Octant 8: shallow up-right. (0, 3) -> (10, 0).
300// ==========================================================================
301
302CESTER_TEST(ls_oct8_start, gpu_raster_phase10,
303 drawLS_oct8();
305)
306CESTER_TEST(ls_oct8_mid, gpu_raster_phase10,
307 drawLS_oct8();
309)
310CESTER_TEST(ls_oct8_end, gpu_raster_phase10,
311 drawLS_oct8();
313)
314
315// ==========================================================================
316// Reverse-direction lines. Hardware should draw the same pixel set as
317// the forward-direction equivalent.
318// ==========================================================================
319
320CESTER_TEST(lr_horiz_start_10_5, gpu_raster_phase10,
321 drawLR_horiz();
323)
324CESTER_TEST(lr_horiz_end_5_5, gpu_raster_phase10,
325 drawLR_horiz();
326 /* End vertex of a reverse-direction line - drawn or excluded? */
328)
329CESTER_TEST(lr_horiz_mid_7_5, gpu_raster_phase10,
330 drawLR_horiz();
332)
333
334CESTER_TEST(lr_vert_start_5_10, gpu_raster_phase10,
335 drawLR_vert();
337)
338CESTER_TEST(lr_vert_end_5_5, gpu_raster_phase10,
339 drawLR_vert();
341)
342CESTER_TEST(lr_vert_mid_5_7, gpu_raster_phase10,
343 drawLR_vert();
345)
346
347// ==========================================================================
348// Clipping at draw-area edges.
349// ==========================================================================
350
351CESTER_TEST(lc_right_inside_8, gpu_raster_phase10,
352 drawLC_right();
353 /* Pixel inside the clipped draw area. */
355)
356CESTER_TEST(lc_right_just_inside_edge_11, gpu_raster_phase10,
357 drawLC_right();
358 /* x=11 - last column inside draw-area (X1=12 exclusive)? */
360)
361CESTER_TEST(lc_right_clipped_15, gpu_raster_phase10,
362 drawLC_right();
363 /* x=15 - past draw-area, must not be drawn. */
365)
366
367CESTER_TEST(lc_bottom_inside_8, gpu_raster_phase10,
368 drawLC_bottom();
370)
371CESTER_TEST(lc_bottom_just_inside_edge_11, gpu_raster_phase10,
372 drawLC_bottom();
374)
375CESTER_TEST(lc_bottom_clipped_15, gpu_raster_phase10,
376 drawLC_bottom();
378)
379
380// ==========================================================================
381// Zero-length at different positions. Should be exactly one pixel.
382// ==========================================================================
383
384CESTER_TEST(lz_at_origin, gpu_raster_phase10,
385 drawLZ_at(0, 0);
387)
388CESTER_TEST(lz_at_origin_neighbor, gpu_raster_phase10,
389 drawLZ_at(0, 0);
391)
392CESTER_TEST(lz_at_5_5, gpu_raster_phase10,
393 drawLZ_at(5, 5);
395)
396CESTER_TEST(lz_at_5_5_neighbor, gpu_raster_phase10,
397 drawLZ_at(5, 5);
399)
400
401// ==========================================================================
402// Gouraud line: red -> blue across 10 pixels at y=5.
403// Per-pixel color interpolation along the Bresenham step.
404// ==========================================================================
405
406CESTER_TEST(lg_start_pure_red, gpu_raster_phase10,
407 drawLG();
409)
410CESTER_TEST(lg_mid_5, gpu_raster_phase10,
411 drawLG();
412 ASSERT_PIXEL_EQ(LG_MID, 5, 5);
413)
414CESTER_TEST(lg_end_10, gpu_raster_phase10,
415 drawLG();
416 ASSERT_PIXEL_EQ(LG_END, 10, 5);
417)
418
419// ==========================================================================
420// Polyline: 3 vertices, 2 segments. Apex (5, 5) is shared between
421// segments - must be drawn exactly once, not double-written or skipped.
422// ==========================================================================
423
424CESTER_TEST(lp_first_segment_start, gpu_raster_phase10,
425 drawLP();
427)
428CESTER_TEST(lp_first_segment_mid, gpu_raster_phase10,
429 drawLP();
431)
432CESTER_TEST(lp_apex, gpu_raster_phase10,
433 drawLP();
434 /* Shared vertex between segment 1 and segment 2. */
436)
437CESTER_TEST(lp_second_segment_mid, gpu_raster_phase10,
438 drawLP();
440)
441CESTER_TEST(lp_second_segment_end, gpu_raster_phase10,
442 drawLP();
443 ASSERT_PIXEL_EQ(LP_END, 10, 0);
444)
445
446// ==========================================================================
447// Semi-trans line: GP0(0x42). Per psx-spx the line mask gating is the
448// drawing-area mask bit (E6), not the per-pixel texel mask. Lines have
449// no texture so the semi-trans always applies the blend equation.
450// ==========================================================================
451
452CESTER_TEST(lst_mid_blended, gpu_raster_phase10,
453 drawLST();
454 /* Semi-trans green over red background. Hardware truth captured;
455 likely a 0.5*red + 0.5*green blend = (R=15, G=15, B=0)
456 approximately = vram555(15, 15, 0) = 0x01ef. */
458)
459CESTER_TEST(lst_neighbor_unblended, gpu_raster_phase10,
460 drawLST();
461 /* Outside the line - background red preserved. */
463)
CESTER_TEST(cddaLevelHalf, test_instances, static const uint8_t atv[4]={0x40, 0x00, 0x40, 0x00};unsigned changes=0;int peak=cddaPeak(atv, 1, &changes);ramsyscall_printf("CD-DA level at half ATV: peak %i, %u sign changes\n", peak, changes);cester_assert_int_ge(peak, 11300);cester_assert_int_le(peak, 11800);cester_assert_uint_ge(changes, 4);) CESTER_TEST(cddaLevelClipped
CESTER_BODY(static uint16_t s_cddaCapture;static int cddaSpuDma(uint32_t spuAddr, void *buf, uint32_t bytes, int isRead) { const uint16_t tsa=spuAddr > > 3;const uint16_t mode=isRead ? 0x30 :0x20;SPU_RAM_DTA=tsa;for(int i=0;i< 0xf01 &&SPU_RAM_DTA !=tsa;i++);SPU_CTRL=(SPU_CTRL &~0x30)|mode;for(volatile int i=0;i< 60;i++);for(int i=0;i< 0xf01 &&(SPU_STATUS &0x30) !=mode;i++);CDDA_SPU_DELAY=(CDDA_SPU_DELAY &0xf0ffffff)|(isRead ? 0x22000000 :0x20000000);DMA_CTRL[DMA_SPU].MADR=(uint32_t) buf &0x1fffffff;DMA_CTRL[DMA_SPU].BCR=((bytes > > 6)<< 16)|0x10;DMA_CTRL[DMA_SPU].CHCR=isRead ? 0x01000200 :0x01000201;int ok=0;for(unsigned t=0;t< 4000000u;t++) { if((DMA_CTRL[DMA_SPU].CHCR &0x01000000)==0) { ok=1;break;} } SPU_CTRL=SPU_CTRL &~0x30;for(volatile int i=0;i< 60;i++);return ok;} static int cddaSimpleCmd(uint8_t cmd) { uint8_t response[16];CDROM_REG0=0;CDROM_REG1=cmd;uint32_t timeout=2000000;int ok=waitCDRomIRQWithTimeout(&timeout);ackCDRomCause();readResponse(response);return ok;} static void cddaWaitPauseComplete() { initializeTime();uint32_t elapsed=0;while(elapsed< 5000000u) { uint32_t budget=200000u;int ok=waitCDRomIRQWithTimeout(&budget);elapsed=budget;if(!ok) continue;uint8_t cause=ackCDRomCause();uint8_t response[16];readResponse(response);if(cause==2) return;} } static int cddaAudioSetup(const uint8_t atv[4], int demute) { if(!resetCDRom()) return 0;DPCR|=0x000b0000;SPU_CTRL=0;for(volatile int i=0;i< 20000;i++);SPU_VOL_MAIN_LEFT=0;SPU_VOL_MAIN_RIGHT=0;SPU_KEY_OFF_LOW=0xffff;SPU_KEY_OFF_HIGH=0xffff;SPU_RAM_DTC=4;SPU_CTRL=0x8001;for(volatile int i=0;i< 20000;i++);for(int i=0;i< 0x400;i++) s_cddaCapture[i]=CDDA_MARKER;if(!cddaSpuDma(0x000, s_cddaCapture, 0x800, 0)) return 0;if(!cddaSimpleCmd(demute ? CDL_DEMUTE :CDL_MUTE)) return 0;CDROM_REG0=2;CDROM_REG2=atv[0];CDROM_REG3=atv[1];CDROM_REG0=3;CDROM_REG1=atv[2];CDROM_REG2=atv[3];CDROM_REG0=3;CDROM_REG3=0x20;CDROM_REG0=0;SPU_VOL_CD_LEFT=0x7fff;SPU_VOL_CD_RIGHT=0x7fff;SPU_CTRL=SPU_CTRL|0x8001;return 1;} static int cddaBufferPeak(unsigned *signChanges) { int peak=0;unsigned changes=0;int prev=0;for(int i=0;i< 0x200;i++) { int v=(int16_t) s_cddaCapture[i];int a=v< 0 ? -v :v;if(a > peak) peak=a;int sign=v >=0 ? 1 :-1;if(i &&sign !=prev) changes++;prev=sign;} *signChanges=changes;return peak;} static int cddaCapturePeak(unsigned *signChanges) { int peak=0;for(unsigned attempt=0;attempt< 8;attempt++) { if(attempt) { initializeTime();while(updateTime()< 250000u);} if(!cddaSpuDma(0x000, s_cddaCapture, 0x800, 1)) return -1;peak=cddaBufferPeak(signChanges);if(peak) { if(attempt) ramsyscall_printf("capture was empty %u time(s) before audio\n", attempt);break;} } return peak;} static int cddaPeak(const uint8_t atv[4], int demute, unsigned *signChanges) { if(!cddaAudioSetup(atv, demute)) return -1;if(!setMode(0)) return -1;CDROM_REG0=0;CDROM_REG2=0x02;if(!cddaSimpleCmd(CDL_PLAY)) return -1;initializeTime();while(updateTime()< 1500000u);int peak=cddaCapturePeak(signChanges);CDROM_REG0=0;CDROM_REG1=CDL_PAUSE;cddaWaitPauseComplete();CDROM_REG0=0;CDROM_REG2=0x00;CDROM_REG2=0x02;CDROM_REG2=0x16;if(cddaSimpleCmd(CDL_SETLOC) &&cddaSimpleCmd(CDL_SEEKL)) cddaWaitPauseComplete();return peak;}[0x400])
Definition cdda.c:37
#define LS_OCT2_END
Definition raster-expected-phase10.h:47
#define LS_OCT7_MID
Definition raster-expected-phase10.h:68
#define LC_RIGHT_JUST_INSIDE
Definition raster-expected-phase10.h:85
#define LS_OCT3_END
Definition raster-expected-phase10.h:52
#define LS_OCT6_MID
Definition raster-expected-phase10.h:64
#define LS_OCT5_END
Definition raster-expected-phase10.h:60
#define LS_OCT3_MID
Definition raster-expected-phase10.h:51
#define LG_START
Definition raster-expected-phase10.h:95
#define LS_OCT6_END
Definition raster-expected-phase10.h:65
#define LR_VERT_END
Definition raster-expected-phase10.h:81
#define LST_MID
Definition raster-expected-phase10.h:110
#define LS_OCT5_MID
Definition raster-expected-phase10.h:59
#define LP_END
Definition raster-expected-phase10.h:100
#define LS_OCT4_MID
Definition raster-expected-phase10.h:55
#define LS_OCT2_Y5_X1
Definition raster-expected-phase10.h:45
#define LS_OCT2_Y5_X2
Definition raster-expected-phase10.h:46
#define LS_OCT4_END
Definition raster-expected-phase10.h:56
#define LG_MID
Definition raster-expected-phase10.h:96
#define LC_BOTTOM_JUST_INSIDE
Definition raster-expected-phase10.h:86
#define LS_OCT8_END
Definition raster-expected-phase10.h:74
#define LR_HORIZ_END
Definition raster-expected-phase10.h:80
#define LS_OCT8_MID
Definition raster-expected-phase10.h:73
#define LG_END
Definition raster-expected-phase10.h:97
#define LS_OCT7_END
Definition raster-expected-phase10.h:69
#define RASTER_VRAM_GREEN
Definition raster-helpers.h:127
#define RASTER_DRAW_AREA_Y2
Definition raster-helpers.h:70
#define RASTER_VRAM_BLUE
Definition raster-helpers.h:129
#define RASTER_VRAM_WHITE
Definition raster-helpers.h:131
#define RASTER_DRAW_AREA_X1
Definition raster-helpers.h:67
#define ASSERT_PIXEL_UNTOUCHED(x_, y_)
Definition raster-helpers.h:486
#define RASTER_DRAW_AREA_Y1
Definition raster-helpers.h:68
#define RASTER_VRAM_RED
Definition raster-helpers.h:125
#define RASTER_CMD_BLUE
Definition raster-helpers.h:128
#define RASTER_CMD_RED
Definition raster-helpers.h:124
#define RASTER_CMD_WHITE
Definition raster-helpers.h:130
#define RASTER_CMD_GREEN
Definition raster-helpers.h:126
#define ASSERT_PIXEL_EQ(expected, x_, y_)
Definition raster-helpers.h:473
#define RASTER_DRAW_AREA_X2
Definition raster-helpers.h:69