Citro3d
Loading...
Searching...
No Matches
texture.c
Go to the documentation of this file.
1#include "internal.h"
2#include <c3d/renderqueue.h>
3
4// Return bits per pixel
5static inline size_t fmtSize(GPU_TEXCOLOR fmt)
6{
7 switch (fmt)
8 {
9 case GPU_RGBA8:
10 return 32;
11 case GPU_RGB8:
12 return 24;
13 case GPU_RGBA5551:
14 case GPU_RGB565:
15 case GPU_RGBA4:
16 case GPU_LA8:
17 case GPU_HILO8:
18 return 16;
19 case GPU_L8:
20 case GPU_A8:
21 case GPU_LA4:
22 case GPU_ETC1A4:
23 return 8;
24 case GPU_L4:
25 case GPU_A4:
26 case GPU_ETC1:
27 return 4;
28 default:
29 return 0;
30 }
31}
32
33static inline bool checkTexSize(u32 size)
34{
35 if (size < 8 || size > 1024)
36 return false;
37 if (size & (size-1))
38 return false;
39 return true;
40}
41
42static inline void allocFree(void* addr)
43{
44 if (addrIsVRAM(addr))
45 vramFree(addr);
46 else
47 linearFree(addr);
48}
49
50static void C3Di_TexCubeDelete(C3D_TexCube* cube)
51{
52 int i;
53 for (i = 0; i < 6; i ++)
54 {
55 if (cube->data[i])
56 {
57 allocFree(cube->data[i]);
58 cube->data[i] = NULL;
59 }
60 }
61}
62
63bool C3D_TexInitWithParams(C3D_Tex* tex, C3D_TexCube* cube, C3D_TexInitParams p)
64{
65 if (!checkTexSize(p.width) || !checkTexSize(p.height)) return false;
66
67 bool isCube = typeIsCube(p.type);
68 if (isCube && !cube) return false;
69
70 u32 size = fmtSize(p.format);
71 if (!size) return false;
72 size *= (u32)p.width * p.height / 8;
73 u32 total_size = C3D_TexCalcTotalSize(size, p.maxLevel);
74
75 if (!isCube)
76 {
77 tex->data = p.onVram ? vramAlloc(total_size) : linearAlloc(total_size);
78 if (!tex->data) return false;
79 } else
80 {
81 memset(cube, 0, sizeof(*cube));
82 int i;
83 for (i = 0; i < 6; i ++)
84 {
85 cube->data[i] = p.onVram ? vramAlloc(total_size) : linearAlloc(total_size);
86 if (!cube->data[i] ||
87 (i>0 && (((u32)cube->data[0] ^ (u32)cube->data[i])>>(3+22)))) // Check upper 6bits match with first face
88 {
89 C3Di_TexCubeDelete(cube);
90 return false;
91 }
92 }
93 tex->cube = cube;
94 }
95
96 tex->width = p.width;
97 tex->height = p.height;
98 tex->param = GPU_TEXTURE_MODE(p.type);
99 if (p.format == GPU_ETC1)
100 tex->param |= GPU_TEXTURE_ETC1_PARAM;
101 if (p.type == GPU_TEX_SHADOW_2D || p.type == GPU_TEX_SHADOW_CUBE)
102 tex->param |= GPU_TEXTURE_SHADOW_PARAM;
103 tex->fmt = p.format;
104 tex->size = size;
105 tex->border = 0;
106 tex->lodBias = 0;
107 tex->maxLevel = p.maxLevel;
108 tex->minLevel = 0;
109 return true;
110}
111
112void C3D_TexLoadImage(C3D_Tex* tex, const void* data, GPU_TEXFACE face, int level)
113{
114 u32 size = 0;
115 void* out = C3D_TexGetImagePtr(tex,
116 C3Di_TexIs2D(tex) ? tex->data : tex->cube->data[face],
117 level, &size);
118
119 if (!addrIsVRAM(out))
120 memcpy(out, data, size);
121 else
122 C3D_SyncTextureCopy((u32*)data, 0, (u32*)out, 0, size, 8);
123}
124
125static void C3Di_DownscaleRGBA8(u32* dst, const u32* src[4])
126{
127 u32 i, j;
128 for (i = 0; i < 64; i ++)
129 {
130 const u32* a = src[i>>4] + (i<<2 & 0x3F);
131 u32 dest = 0;
132 for (j = 0; j < 32; j += 8)
133 {
134 u32 val = (((a[0]>>j)&0xFF)+((a[1]>>j)&0xFF)+((a[2]>>j)&0xFF)+((a[3]>>j)&0xFF))>>2;
135 dest |= val<<j;
136 }
137 *dst++ = dest;
138 }
139}
140
141static void C3Di_DownscaleRGB8(u8* dst, const u8* src[4])
142{
143 u32 i, j;
144 for (i = 0; i < 64; i ++)
145 {
146 const u8* a = src[i>>4] + 3*(i<<2 & 0x3F);
147 for (j = 0; j < 3; j ++)
148 {
149 *dst++ = ((u32)a[0] + a[3] + a[6] + a[9])>>2;
150 a++;
151 }
152 }
153}
154
155void C3D_TexGenerateMipmap(C3D_Tex* tex, GPU_TEXFACE face)
156{
157 int fmt = tex->fmt;
158 size_t block_size = (8*8*fmtSize(fmt))/8;
159
160 /*
161 const u32 transfer_flags =
162 GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_XY) | BIT(5) |
163 GX_TRANSFER_IN_FORMAT(tex->fmt) | GX_TRANSFER_OUT_FORMAT(tex->fmt);
164 */
165
166 void* src = C3Di_TexIs2D(tex) ? tex->data : tex->cube->data[face];
167 if (addrIsVRAM(src))
168 return; // CPU can't write to VRAM
169
170 int i;
171 u32 level_size = tex->size;
172 u32 src_width = tex->width;
173 u32 src_height = tex->height;
174 for (i = 0; i < tex->maxLevel; i ++)
175 {
176 void* dst = (u8*)src + level_size;
177 u32 dst_width = src_width>>1;
178 u32 dst_height = src_height>>1;
179
180 /* Doesn't work due to size restriction bullshit
181 C3D_SyncDisplayTransfer(
182 (u32*)src, GX_BUFFER_DIM(src_width,src_height),
183 (u32*)dst, GX_BUFFER_DIM(dst_width,dst_height),
184 transfer_flags);
185 */
186
187 u32 i,j;
188 u32 src_stride = src_width/8;
189 u32 dst_stride = dst_width/8;
190 for (j = 0; j < (dst_height/8); j ++)
191 {
192 for (i = 0; i < dst_stride; i ++)
193 {
194 void* dst_block = (u8*)dst + block_size*(i + j*dst_stride);
195 const void* src_blocks[4] =
196 {
197 (u8*)src + block_size*(2*i+0 + (2*j+0)*src_stride),
198 (u8*)src + block_size*(2*i+1 + (2*j+0)*src_stride),
199 (u8*)src + block_size*(2*i+0 + (2*j+1)*src_stride),
200 (u8*)src + block_size*(2*i+1 + (2*j+1)*src_stride),
201 };
202 switch (fmt)
203 {
204 case GPU_RGBA8:
205 C3Di_DownscaleRGBA8(dst_block, (const u32**)src_blocks);
206 break;
207 case GPU_RGB8:
208 C3Di_DownscaleRGB8(dst_block, (const u8**)src_blocks);
209 default:
210 break;
211 }
212 }
213 }
214
215 level_size >>= 2;
216 src = dst;
217 src_width = dst_width;
218 src_height = dst_height;
219 }
220}
221
222void C3D_TexBind(int unitId, C3D_Tex* tex)
223{
224 C3D_Context* ctx = C3Di_GetContext();
225
226 if (!(ctx->flags & C3DiF_Active))
227 return;
228
229 if (unitId > 0 && C3D_TexGetType(tex) != GPU_TEX_2D)
230 return;
231
232 ctx->flags |= C3DiF_Tex(unitId);
233 ctx->tex[unitId] = tex;
234}
235
236void C3D_TexFlush(C3D_Tex* tex)
237{
238 if (!addrIsVRAM(tex->data))
239 GSPGPU_FlushDataCache(tex->data, C3D_TexCalcTotalSize(tex->size, tex->maxLevel));
240}
241
242void C3D_TexDelete(C3D_Tex* tex)
243{
244 if (C3Di_TexIs2D(tex))
245 allocFree(tex->data);
246 else
247 C3Di_TexCubeDelete(tex->cube);
248}
249
250void C3D_TexShadowParams(bool perspective, float bias)
251{
252 C3D_Context* ctx = C3Di_GetContext();
253
254 if (!(ctx->flags & C3DiF_Active))
255 return;
256
257 u32 iBias = (u32)(fabs(bias) * BIT(24));
258 if (iBias >= BIT(24))
259 iBias = BIT(24)-1;
260
261 ctx->texShadow = (iBias &~ 1) | (perspective ? 0 : 1);
262 ctx->flags |= C3DiF_TexStatus;
263}
264
265void C3Di_SetTex(int unit, C3D_Tex* tex)
266{
267 u32 reg[10];
268 u32 regcount = 5;
269 reg[0] = tex->border;
270 reg[1] = tex->dim;
271 reg[2] = tex->param;
272 reg[3] = tex->lodParam;
273 if (C3Di_TexIs2D(tex))
274 reg[4] = osConvertVirtToPhys(tex->data) >> 3;
275 else
276 {
277 int i;
278 C3D_TexCube* cube = tex->cube;
279 regcount = 10;
280 reg[4] = osConvertVirtToPhys(cube->data[0]) >> 3;
281 for (i = 1; i < 6; i ++)
282 reg[4+i] = (osConvertVirtToPhys(cube->data[i]) >> 3) & 0x3FFFFF;
283 }
284
285 switch (unit)
286 {
287 case 0:
288 GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT0_BORDER_COLOR, reg, regcount);
289 GPUCMD_AddWrite(GPUREG_TEXUNIT0_TYPE, tex->fmt);
290 break;
291 case 1:
292 GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT1_BORDER_COLOR, reg, 5);
293 GPUCMD_AddWrite(GPUREG_TEXUNIT1_TYPE, tex->fmt);
294 break;
295 case 2:
296 GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT2_BORDER_COLOR, reg, 5);
297 GPUCMD_AddWrite(GPUREG_TEXUNIT2_TYPE, tex->fmt);
298 break;
299 }
300}
@ C3DiF_Active
Definition: internal.h:75
@ C3DiF_TexStatus
Definition: internal.h:88
#define C3DiF_Tex(n)
Definition: internal.h:97
void C3D_SyncTextureCopy(u32 *inadr, u32 indim, u32 *outadr, u32 outdim, u32 size, u32 flags)
Definition: renderqueue.c:430
u32 flags
Definition: internal.h:38
C3D_Tex * tex[3]
Definition: internal.h:48
u32 texShadow
Definition: internal.h:47
void C3D_TexFlush(C3D_Tex *tex)
Definition: texture.c:236
void C3D_TexBind(int unitId, C3D_Tex *tex)
Definition: texture.c:222
void C3Di_SetTex(int unit, C3D_Tex *tex)
Definition: texture.c:265
void C3D_TexGenerateMipmap(C3D_Tex *tex, GPU_TEXFACE face)
Definition: texture.c:155
void C3D_TexLoadImage(C3D_Tex *tex, const void *data, GPU_TEXFACE face, int level)
Definition: texture.c:112
void C3D_TexShadowParams(bool perspective, float bias)
Definition: texture.c:250
void C3D_TexDelete(C3D_Tex *tex)
Definition: texture.c:242
bool C3D_TexInitWithParams(C3D_Tex *tex, C3D_TexCube *cube, C3D_TexInitParams p)
Definition: texture.c:63
float24Uniform_s * data
Definition: uniforms.c:16