1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 // Disable printf override in common/forbidden.h to avoid
24 // clashes with pspdebug.h from the PSP SDK.
25 // That header file uses
26 // __attribute__((format(printf,1,2)));
27 // which gets messed up by our override mechanism; this could
28 // be avoided by either changing the PSP SDK to use the equally
29 // legal and valid
30 // __attribute__((format(__printf__,1,2)));
31 // or by refining our printf override to use a varadic macro
32 // (which then wouldn't be portable, though).
33 // Anyway, for now we just disable the printf override globally
34 // for the PSP port
35 #define FORBIDDEN_SYMBOL_EXCEPTION_printf
36
37 #include <pspgu.h>
38 #include <pspkerneltypes.h>
39 #include <pspdisplay.h>
40 #include <psputils.h>
41
42 #include "common/scummsys.h"
43 #include "backends/platform/psp/psppixelformat.h"
44 #include "backends/platform/psp/display_client.h"
45 #include "backends/platform/psp/display_manager.h"
46 #define PSP_INCLUDE_SWAP
47 #include "backends/platform/psp/memory.h"
48
49 //#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
50 //#define __PSP_DEBUG_PRINT__
51 #include "backends/platform/psp/trace.h"
52
53 #define PSP_BUFFER_WIDTH (512)
54 #define PSP_SCREEN_WIDTH 480
55 #define PSP_SCREEN_HEIGHT 272
56 #define PSP_FRAME_SIZE (PSP_BUFFER_WIDTH * PSP_SCREEN_HEIGHT)
57
58 DisplayManager *GuRenderer::_displayManager = 0;
59
60
61 // class Palette ------------------------------------------------------------
62 //
clear()63 void Palette::clear() {
64 DEBUG_ENTER_FUNC();
65
66 if (_values && _numOfEntries)
67 memset(_values, 0, getSizeInBytes());
68
69 PSP_DEBUG_PRINT("_values[%p]\n", _values);
70 }
71
72 // Used to clear the specific keycolor
73 //
setColorPositionAlpha(uint32 position,bool alpha)74 void Palette::setColorPositionAlpha(uint32 position, bool alpha) {
75 DEBUG_ENTER_FUNC();
76
77 assert(_values);
78 assert(position < _numOfEntries);
79
80 PSP_DEBUG_PRINT("position[%d], numofEntries[%u], bpp[%u], values[%p]\n", position, _numOfEntries,
81 _pixelFormat.bitsPerPixel, _values);
82
83 if (_numOfEntries <= 16)
84 position &= 0xF;
85 else if (_numOfEntries <= 256)
86 position &= 0xFF;
87
88 switch (_pixelFormat.bitsPerPixel) {
89 case 16: {
90 uint16 *shortVal = (uint16 *) & _values[_pixelFormat.pixelsToBytes(position)];
91 *shortVal = _pixelFormat.setColorAlpha((uint32) * shortVal, alpha ? 255 : 0);
92 }
93 break;
94 case 32: {
95 uint32 *wordVal = (uint32 *) & _values[_pixelFormat.pixelsToBytes(position)];
96 *wordVal = _pixelFormat.setColorAlpha((uint32) * wordVal, alpha ? 255 : 0);
97 }
98 break;
99 default:
100 PSP_ERROR("Incorrect bits per pixel value[%u]\n", _pixelFormat.bitsPerPixel);
101 }
102 }
103
104 // Set some of the palette to color values in array
105 // By default, ScummVm doesn't support alpha values in palettes
setPartial(const byte * colors,uint32 start,uint32 num,bool supportsAlpha)106 void Palette::setPartial(const byte *colors, uint32 start, uint32 num, bool supportsAlpha /* = false */) {
107 DEBUG_ENTER_FUNC();
108
109 assert(_values);
110 assert(_numOfEntries);
111
112 const byte *src = colors;
113
114 if (start + num > _numOfEntries) // Check boundary
115 num = _numOfEntries - start;
116
117 if (_pixelFormat.bitsPerPixel == 16) {
118 uint16 *palette = (uint16 *)_values;
119 palette += start;
120
121 for (uint32 i = 0; i < num; ++i) {
122 byte alphaVal = supportsAlpha ? src[3] : 0xFF;
123 *palette = (uint16)_pixelFormat.rgbaToColor(src[0], src[1], src[2], alphaVal);
124 src += 3;
125 palette++;
126 }
127 } else if (_pixelFormat.bitsPerPixel == 32) {
128 uint32 *palette = (uint32 *)_values;
129 palette += start;
130
131 for (uint32 i = 0; i < num; ++i) {
132 byte alphaVal = supportsAlpha ? src[3] : 0xFF;
133 *palette = _pixelFormat.rgbaToColor(src[0], src[1], src[2], alphaVal);
134 src += 3;
135 palette++;
136 }
137 }
138 }
139
140 // Sets pixel format and number of entries by the buffer's pixel format */
setPixelFormats(PSPPixelFormat::Type paletteType,PSPPixelFormat::Type bufferType,bool swapRedBlue)141 void Palette::setPixelFormats(PSPPixelFormat::Type paletteType, PSPPixelFormat::Type bufferType, bool swapRedBlue /* = false */) {
142 DEBUG_ENTER_FUNC();
143
144 if (paletteType == PSPPixelFormat::Type_Unknown)
145 PSP_ERROR("Unknown paletteType[%u]\n", paletteType);
146
147 switch (bufferType) {
148 case PSPPixelFormat::Type_Palette_8bit:
149 _numOfEntries = 256;
150 break;
151 case PSPPixelFormat::Type_Palette_4bit:
152 _numOfEntries = 16;
153 break;
154 case PSPPixelFormat::Type_Unknown:
155 case PSPPixelFormat::Type_None:
156 PSP_ERROR("Unhandled bufferType[%u]\n", bufferType);
157 break;
158 default: // No palette
159 _numOfEntries = 0;
160 break;
161 }
162
163 _pixelFormat.set(paletteType, swapRedBlue);
164 }
165
allocate()166 bool Palette::allocate() {
167 DEBUG_ENTER_FUNC();
168 PSP_DEBUG_PRINT("_numOfEntries[%u]\n", _numOfEntries);
169 PSP_DEBUG_PRINT("_pixelFormat: format[%u], bpp[%u]\n", _pixelFormat.format, _pixelFormat.bitsPerPixel);
170
171 if (_values) {
172 free(CACHED(_values));
173 _values = 0;
174 }
175
176 // We allocate on 64bytes to get a cache line, and round up to 64bytes to get the full line
177 uint32 amountInBytes = getSizeInBytes();
178 if (amountInBytes < 64)
179 amountInBytes = 64;
180 _values = (byte *)memalign(64, amountInBytes);
181
182 // Use uncached memory
183 GuRenderer::cacheInvalidate(_values, amountInBytes);
184 _values = UNCACHED(_values);
185
186 if (!_values) {
187 PSP_ERROR("Couldn't allocate palette.\n");
188 return false;
189 }
190
191 PSP_DEBUG_PRINT("_values[%p]\n", _values);
192 clear();
193
194 return true;
195 }
196
deallocate()197 void Palette::deallocate() {
198 DEBUG_ENTER_FUNC();
199
200 free(CACHED(_values));
201 _values = 0;
202 _numOfEntries = 0;
203 }
204
205 // Copy some of the palette to an array of colors
206 //
getPartial(byte * colors,uint start,uint num) const207 void Palette::getPartial(byte *colors, uint start, uint num) const {
208 DEBUG_ENTER_FUNC();
209
210 assert(_values);
211 assert(_numOfEntries);
212
213 uint32 r, g, b, a;
214
215 if (start + num > _numOfEntries) // Check boundary
216 num = _numOfEntries - start;
217
218 if (_pixelFormat.bitsPerPixel == 16) {
219 uint16 *palette = (uint16 *)_values;
220 palette += start;
221
222 for (uint32 i = start; i < start + num; i++) {
223 _pixelFormat.colorToRgba(*palette, r, g, b, a);
224
225 *colors++ = (byte)r;
226 *colors++ = (byte)g;
227 *colors++ = (byte)b;
228 palette++;
229 }
230 } else if (_pixelFormat.bitsPerPixel == 32) {
231 uint32 *palette = (uint32 *)_values;
232 palette += start;
233
234 for (uint32 i = start; i < start + num; i++) {
235 _pixelFormat.colorToRgba(*palette, r, g, b, a);
236
237 *colors++ = (byte)r;
238 *colors++ = (byte)g;
239 *colors++ = (byte)b;
240 palette++;
241 }
242 }
243 }
244
setSingleColorRGBA(uint32 num,byte r,byte g,byte b,byte a)245 void Palette::setSingleColorRGBA(uint32 num, byte r, byte g, byte b, byte a) {
246 // DEBUG_ENTER_FUNC();
247 uint16 *shortValues;
248 uint32 *wordValues;
249
250 assert(_values);
251 assert(num < _numOfEntries);
252
253 switch (_pixelFormat.bitsPerPixel) {
254 case 16:
255 shortValues = (uint16 *)_values;
256 shortValues[num] = _pixelFormat.rgbaToColor(r, g, b, a);
257 break;
258 case 32:
259 wordValues = (uint32 *)_values;
260 wordValues[num] = _pixelFormat.rgbaToColor(r, g, b, a);
261 break;
262 default:
263 PSP_ERROR("Incorrect bitsPerPixel[%d]\n", _pixelFormat.bitsPerPixel);
264 break;
265 }
266 }
267
268 // Print to screen
print(uint32 numToPrint)269 void Palette::print(uint32 numToPrint /* = 0 */) {
270 if (_numOfEntries > 0) {
271 assert(_values);
272
273 if (numToPrint > _numOfEntries || numToPrint == 0)
274 numToPrint = _numOfEntries;
275
276 PSP_INFO_PRINT("cursor palette:\n");
277
278 for (unsigned int i = 0; i < numToPrint; i++) {
279 byte *pcolor = &_values[_pixelFormat.pixelsToBytes(i)];
280 uint32 color = _pixelFormat.getColorValueAt(pcolor);
281
282 PSP_INFO_PRINT("[%u=%x] ", i, color);
283 }
284
285 PSP_INFO_PRINT("\n");
286 }
287 }
288
getRawColorAt(uint32 position) const289 uint32 Palette::getRawColorAt(uint32 position) const {
290 byte *pcolor = &_values[_pixelFormat.pixelsToBytes(position)];
291 uint32 color = _pixelFormat.getColorValueAt(pcolor);
292 return color;
293 }
294
getRGBAColorAt(uint32 position) const295 uint32 Palette::getRGBAColorAt(uint32 position) const {
296 uint32 color = getRawColorAt(position);
297 uint32 r, g, b, a;
298 _pixelFormat.colorToRgba(color, r, g, b, a);
299 return (a << 24 | b << 16 | g << 8 | r);
300 }
301
302 // class Buffer ---------------------------------------------------
303
setPixelFormat(PSPPixelFormat::Type type,bool swapRedBlue)304 void Buffer::setPixelFormat(PSPPixelFormat::Type type, bool swapRedBlue) {
305 if (type == PSPPixelFormat::Type_None ||
306 type == PSPPixelFormat::Type_Unknown)
307 PSP_ERROR("Unhandled buffer format[%u]\n", type);
308
309 _pixelFormat.set(type, swapRedBlue);
310 }
311
hasPalette()312 bool Buffer::hasPalette() {
313 if (_pixelFormat.format == PSPPixelFormat::Type_Palette_8bit ||
314 _pixelFormat.format == PSPPixelFormat::Type_Palette_4bit)
315 return true;
316
317 return false;
318 }
319
320 /* pitch is in bytes */
copyFromArray(const byte * buffer,int pitch)321 void Buffer::copyFromArray(const byte *buffer, int pitch) {
322 DEBUG_ENTER_FUNC();
323
324 // We use sourceSize because outside, they won't know what the true size is
325 copyFromRect(buffer, pitch, 0, 0, _sourceSize.width, _sourceSize.height);
326 }
327
328 /* pitch is in bytes */
copyFromRect(const byte * buf,uint32 pitch,int destX,int destY,uint32 recWidth,uint32 recHeight)329 void Buffer::copyFromRect(const byte *buf, uint32 pitch, int destX, int destY, uint32 recWidth, uint32 recHeight) {
330 // Removed silly clipping code
331 DEBUG_ENTER_FUNC();
332 assert(_pixels);
333
334 if (recWidth > _sourceSize.width - destX) {
335 recWidth = _sourceSize.width - destX;
336 }
337
338 if (recHeight > _sourceSize.height - destY) {
339 recHeight = _sourceSize.height - destY;
340 }
341
342 if (recWidth <= 0 || recHeight <= 0) {
343 return;
344 }
345
346 byte *dst = _pixels + _pixelFormat.pixelsToBytes((destY * _width) + destX);
347
348 uint32 recWidthInBytes = _pixelFormat.pixelsToBytes(recWidth);
349 uint32 realWidthInBytes = _pixelFormat.pixelsToBytes(_width);
350
351 if (pitch == realWidthInBytes && pitch == recWidthInBytes) {
352 //memcpy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth));
353 if (_pixelFormat.swapRB)
354 PspMemorySwap::fastSwap(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth), _pixelFormat);
355 else
356 PspMemory::fastCopy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth));
357 } else {
358 do {
359 if (_pixelFormat.swapRB)
360 PspMemorySwap::fastSwap(dst, buf, recWidthInBytes, _pixelFormat);
361 else
362 PspMemory::fastCopy(dst, buf, recWidthInBytes);
363 buf += pitch;
364 dst += realWidthInBytes;
365 } while (--recHeight);
366 }
367 }
368
369 /* pitch is in bytes */
copyToArray(byte * dst,int pitch)370 void Buffer::copyToArray(byte *dst, int pitch) {
371 DEBUG_ENTER_FUNC();
372 assert(_pixels);
373
374 uint32 h = _height;
375 byte *src = _pixels;
376 uint32 sourceWidthInBytes = _pixelFormat.pixelsToBytes(_sourceSize.width);
377 uint32 realWidthInBytes = _pixelFormat.pixelsToBytes(_width);
378
379 do {
380 //memcpy(dst, src, sourceWidthInBytes);
381 if (_pixelFormat.swapRB)
382 PspMemorySwap::fastSwap(dst, src, sourceWidthInBytes, _pixelFormat);
383 else
384 PspMemory::fastCopy(dst, src, sourceWidthInBytes);
385 src += realWidthInBytes;
386 dst += pitch;
387 } while (--h);
388 }
389
setSize(uint32 width,uint32 height,HowToSize textureOrSource)390 void Buffer::setSize(uint32 width, uint32 height, HowToSize textureOrSource/*=kSizeByTextureSize*/) {
391 DEBUG_ENTER_FUNC();
392
393 // We can size the buffer either by texture size (multiple of 2^n) or source size.
394 // At higher sizes, increasing the texture size to 2^n is a waste of space. At these sizes kSizeBySourceSize should be used.
395
396 _sourceSize.width = width;
397 _sourceSize.height = height;
398
399 _textureSize.width = scaleUpToPowerOfTwo(width); // can only scale up to 512
400 _textureSize.height = scaleUpToPowerOfTwo(height);
401
402 if (textureOrSource == kSizeByTextureSize) {
403 _width = _textureSize.width;
404 _height = _textureSize.height;
405 } else { // sizeBySourceSize
406 _width = _sourceSize.width;
407 _height = _sourceSize.height;
408
409 // adjust allocated width to be divisible by 32.
410 // The GU can only handle multiples of 16 bytes. A 4 bit image x 32 will give us 16 bytes
411 // We don't necessarily know the depth of the pixels here. So just make it divisible by 32.
412 uint32 checkDiv = _width & 31;
413 if (checkDiv)
414 _width += 32 - checkDiv;
415 }
416
417 PSP_DEBUG_PRINT("width[%u], height[%u], texW[%u], texH[%u], sourceW[%d], sourceH[%d] %s\n", _width, _height, _textureSize.width, _textureSize.height, _sourceSize.width, _sourceSize.height, textureOrSource ? "size by source" : "size by texture");
418 }
419
420 // Scale a dimension (width/height) up to power of 2 for the texture
421 // Will only go up to 512 since that's the maximum PSP texture size
scaleUpToPowerOfTwo(uint32 size)422 uint32 Buffer::scaleUpToPowerOfTwo(uint32 size) {
423
424 uint32 textureDimension = 16;
425 while (size > textureDimension && textureDimension < 512)
426 textureDimension <<= 1;
427
428 PSP_DEBUG_PRINT("size[%u]. power of 2[%u]\n", size, textureDimension);
429
430 return textureDimension;
431 }
432
allocate(bool inVram)433 bool Buffer::allocate(bool inVram/*=false*/) {
434 DEBUG_ENTER_FUNC();
435
436 PSP_DEBUG_PRINT("_width[%u], _height[%u]\n", _width, _height);
437 PSP_DEBUG_PRINT("_pixelFormat: format[%u], bpp[%u]\n", _pixelFormat.format, _pixelFormat.bitsPerPixel);
438
439 if (_pixels) {
440 if (VramAllocator::isAddressInVram(_pixels)) // Check if in VRAM
441 VramAllocator::instance().deallocate(_pixels);
442 else // not in VRAM
443 free(CACHED(_pixels));
444
445 _pixels = 0;
446 }
447
448 uint32 size = getSizeInBytes();
449
450 if (inVram) {
451 _pixels = (byte *)VramAllocator::instance().allocate(size);
452 }
453
454 if (!_pixels) { // Either we are not in vram or we didn't manage to allocate in vram
455 // Align to 64 bytes. All normal buffer sizes are multiples of 64 anyway
456 _pixels = (byte *)memalign(64, size);
457 }
458
459 if (!_pixels) {
460 PSP_ERROR("couldn't allocate buffer.\n");
461 return false;
462 }
463
464 // Use uncached memory
465 GuRenderer::cacheInvalidate(_pixels, size);
466 _pixels = UNCACHED(_pixels);
467
468 clear();
469 return true;
470 }
471
deallocate()472 void Buffer::deallocate() {
473 DEBUG_ENTER_FUNC();
474
475 if (!_pixels)
476 return;
477
478 if (VramAllocator::isAddressInVram(_pixels)) // Check if in VRAM
479 VramAllocator::instance().deallocate(_pixels);
480 else
481 free(CACHED(_pixels));
482
483 _pixels = 0;
484 }
485
clear()486 void Buffer::clear() {
487 DEBUG_ENTER_FUNC();
488
489 if (_pixels)
490 memset(_pixels, 0, getSizeInBytes());
491 }
492
493 /* Convert 4 bit images to match weird PSP format */
flipNibbles()494 void Buffer::flipNibbles() {
495 DEBUG_ENTER_FUNC();
496
497 if (_pixelFormat.bitsPerPixel != 4)
498 return;
499
500 assert(_pixels);
501
502 uint32 *dest = (uint32 *)_pixels;
503
504 for (uint32 i = 0; i < getSourceHeight(); i++) {
505 for (uint32 j = 0; j < (getWidth() >> 3); j++) { // /8 because we do it in 32bit chunks
506 uint32 val = *dest;
507 *dest++ = ((val >> 4) & 0x0F0F0F0F) | ((val << 4) & 0xF0F0F0F0);
508 }
509 }
510 }
511
512 // Print buffer contents to screen (only source size is printed out)
print(uint32 mask,uint32 numToPrint)513 void Buffer::print(uint32 mask, uint32 numToPrint /*=0*/) {
514 assert(_pixels);
515
516 if (numToPrint > _sourceSize.width * _sourceSize.height || numToPrint == 0)
517 numToPrint = _sourceSize.width * _sourceSize.height;
518
519 PSP_INFO_PRINT("buffer: \n");
520 PSP_INFO_PRINT("width[%u], height[%u]\n\n", _sourceSize.width, _sourceSize.height);
521
522 for (unsigned int i = 0; i < _sourceSize.height; i++) {
523 for (unsigned int j = 0; j < _sourceSize.width; j++) {
524 if (numToPrint <= 0) // check if done
525 break;
526
527 byte *pcolor = &_pixels[_pixelFormat.pixelsToBytes((i * _width) + j)];
528 uint32 color = _pixelFormat.getColorValueAt(pcolor);
529
530 //if (color != 0) PSP_INFO_PRINT("[%x] ", color);
531 PSP_INFO_PRINT("[%x] ", mask & color);
532
533 numToPrint--;
534 }
535 PSP_INFO_PRINT("\n");
536 }
537 PSP_INFO_PRINT("\n");
538 }
539
540 // class GuRenderer -------------------------------------------------
541 //#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
542 //#define __PSP_DEBUG_PRINT__
543
544 #include "backends/platform/psp/trace.h"
545
546
render()547 void GuRenderer::render() {
548 DEBUG_ENTER_FUNC();
549 PSP_DEBUG_PRINT("Buffer[%p] Palette[%p]\n", _buffer->getPixels(), _palette->getRawValues());
550
551 guProgramDrawBehavior();
552
553 if (_buffer->hasPalette())
554 guLoadPalette();
555
556 guProgramTextureFormat();
557
558 // Loop over patches of 512x512 pixel textures and draw them
559 for (uint32 j = 0; j < _buffer->getSourceHeight(); j += 512) {
560 _textureLoadOffset.y = j;
561
562 for (uint32 i = 0; i < _buffer->getSourceWidth(); i += 512) {
563 _textureLoadOffset.x = i;
564
565 guLoadTexture();
566 Vertex *vertices = guGetVertices();
567 fillVertices(vertices);
568
569 guDrawVertices(vertices);
570 }
571 }
572 }
573
guProgramDrawBehavior()574 inline void GuRenderer::guProgramDrawBehavior() {
575 DEBUG_ENTER_FUNC();
576 PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n",
577 _blending ? "on" : "off", _colorTest ? "on" : "off",
578 _alphaReverse ? "on" : "off", _keyColor);
579
580 if (_blending) {
581 sceGuEnable(GU_BLEND);
582
583 if (_alphaReverse) // Reverse the alpha value (ie. 0 is 1) easier to do in some cases
584 sceGuBlendFunc(GU_ADD, GU_ONE_MINUS_SRC_ALPHA, GU_SRC_ALPHA, 0, 0);
585 else // Normal alpha values
586 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
587
588 } else
589 sceGuDisable(GU_BLEND);
590
591 if (_colorTest) {
592 sceGuEnable(GU_COLOR_TEST);
593 sceGuColorFunc(GU_NOTEQUAL, // show only colors not equal to this color
594 _keyColor,
595 0x00ffffff); // match everything but alpha
596 } else
597 sceGuDisable(GU_COLOR_TEST);
598 }
599
guLoadPalette()600 inline void GuRenderer::guLoadPalette() {
601 DEBUG_ENTER_FUNC();
602
603 uint32 mask;
604
605 if (_buffer->getBitsPerPixel() == 4)
606 mask = 0x0F;
607 else if (_buffer->getBitsPerPixel() == 8)
608 mask = 0xFF;
609 else
610 assert(0); /* error */
611
612 PSP_DEBUG_PRINT("numOfEntries[%d]\n", _palette->getNumOfEntries());
613 PSP_DEBUG_PRINT("bpp[%d], pixelformat[%d], mask[%x]\n", _buffer->getBitsPerPixel(), _palette->getPixelFormat(), mask);
614
615 sceGuClutMode(convertToGuPixelFormat(_palette->getPixelFormat()), 0, mask, 0);
616 sceGuClutLoad(_palette->getNumOfEntries() >> 3, // it's in batches of 8 for some reason
617 _palette->getRawValues());
618 }
619
guProgramTextureFormat()620 inline void GuRenderer::guProgramTextureFormat() {
621 DEBUG_ENTER_FUNC();
622 PSP_DEBUG_PRINT("pixelFormat[%d]\n", _buffer->getPixelFormat());
623
624 sceGuTexMode(convertToGuPixelFormat(_buffer->getPixelFormat()), 0, 0, 0);
625 }
626
convertToGuPixelFormat(PSPPixelFormat::Type format)627 inline uint32 GuRenderer::convertToGuPixelFormat(PSPPixelFormat::Type format) {
628 DEBUG_ENTER_FUNC();
629
630 uint32 guFormat = 0;
631
632 switch (format) {
633 case PSPPixelFormat::Type_4444:
634 guFormat = GU_PSM_4444;
635 break;
636 case PSPPixelFormat::Type_5551:
637 guFormat = GU_PSM_5551;
638 break;
639 case PSPPixelFormat::Type_5650:
640 guFormat = GU_PSM_5650;
641 break;
642 case PSPPixelFormat::Type_8888:
643 guFormat = GU_PSM_8888;
644 break;
645 case PSPPixelFormat::Type_Palette_8bit:
646 guFormat = GU_PSM_T8;
647 break;
648 case PSPPixelFormat::Type_Palette_4bit:
649 guFormat = GU_PSM_T4;
650 break;
651 default:
652 break;
653 }
654
655 PSP_DEBUG_PRINT("Pixelformat[%d], guFormat[%d]\n", format, guFormat);
656
657 return guFormat;
658 }
659
guLoadTexture()660 inline void GuRenderer::guLoadTexture() {
661 DEBUG_ENTER_FUNC();
662
663 byte *startPoint = _buffer->getPixels();
664 if (_textureLoadOffset.x)
665 startPoint += _buffer->_pixelFormat.pixelsToBytes(_textureLoadOffset.x);
666 if (_textureLoadOffset.y)
667 startPoint += _buffer->getWidthInBytes() * _textureLoadOffset.y;
668
669 sceGuTexImage(0,
670 _buffer->getTextureWidth(), // texture width (must be power of 2)
671 _buffer->getTextureHeight(), // texture height (must be power of 2)
672 _buffer->getWidth(), // width of a line of the image (to get to the next line)
673 startPoint); // where to start reading
674 }
675
guGetVertices()676 inline Vertex *GuRenderer::guGetVertices() {
677 DEBUG_ENTER_FUNC();
678
679 Vertex *ret = (Vertex *)sceGuGetMemory(2 * sizeof(Vertex));
680
681 return ret;
682 }
683
684 // Fills the vertices. Most of the logic is here.
fillVertices(Vertex * vertices)685 void GuRenderer::fillVertices(Vertex *vertices) {
686 DEBUG_ENTER_FUNC();
687
688 uint32 outputWidth = _displayManager->getOutputWidth();
689 uint32 outputHeight = _displayManager->getOutputHeight();
690
691 // Texture adjustments for eliminating half-pixel artifacts from scaling
692 // Not necessary if we don't scale
693 float textureFix = 0.0f;
694 if (_useGlobalScaler &&
695 (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleY() != 1.0f))
696 textureFix = 0.5f;
697
698 // These coordinates describe an area within the texture. ie. we already loaded a square of texture,
699 // now the coordinates within it are 0 to the edge of the area of the texture we want to draw
700 float textureStartX = textureFix + _offsetInBuffer.x;
701 float textureStartY = textureFix + _offsetInBuffer.y;
702
703 int textureLeftX = _drawSize.width - _textureLoadOffset.x;
704 if (textureLeftX > 512)
705 textureLeftX = 512;
706 int textureLeftY = _drawSize.height - _textureLoadOffset.y;
707 if (textureLeftY > 512)
708 textureLeftY = 512;
709 float textureEndX = -textureFix + _offsetInBuffer.x + textureLeftX;
710 float textureEndY = -textureFix + _offsetInBuffer.y + textureLeftY;
711 // For scaling to the final image size, calculate the gaps on both sides
712 uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0;
713 uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0;
714
715 // Save scaled offset on screen
716 float scaledOffsetOnScreenX = scaleSourceToOutput(true, _offsetOnScreen.x);
717 float scaledOffsetOnScreenY = scaleSourceToOutput(false, _offsetOnScreen.y);
718
719 float imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutput(true, stretch(true, _textureLoadOffset.x)));
720 float imageStartY = gapY + scaledOffsetOnScreenY + (scaleSourceToOutput(false, stretch(false, _textureLoadOffset.y)));
721
722 float imageEndX, imageEndY;
723
724 imageEndX = imageStartX + scaleSourceToOutput(true, stretch(true, textureLeftX));
725 imageEndY = imageStartY + scaleSourceToOutput(false, stretch(false, textureLeftY));
726
727 vertices[0].u = textureStartX;
728 vertices[0].v = textureStartY;
729 vertices[1].u = textureEndX;
730 vertices[1].v = textureEndY;
731
732 vertices[0].x = imageStartX;
733 vertices[0].y = imageStartY;
734 vertices[0].z = 0;
735 vertices[1].x = imageEndX;
736 vertices[1].y = imageEndY;
737 vertices[1].z = 0;
738
739 PSP_DEBUG_PRINT("TextureStart: X[%f] Y[%f] TextureEnd: X[%.1f] Y[%.1f]\n", textureStartX, textureStartY, textureEndX, textureEndY);
740 PSP_DEBUG_PRINT("ImageStart: X[%f] Y[%f] ImageEnd: X[%.1f] Y[%.1f]\n", imageStartX, imageStartY, imageEndX, imageEndY);
741 }
742
743 /* Scale the input X/Y offset to appear in proper position on the screen */
scaleSourceToOutput(bool x,float offset)744 inline float GuRenderer::scaleSourceToOutput(bool x, float offset) {
745 float result;
746
747 if (!_useGlobalScaler)
748 result = offset;
749 else if (!offset)
750 result = 0.0f;
751 else
752 result = x ? offset * _displayManager->getScaleX() : offset * _displayManager->getScaleY();
753
754 return result;
755 }
756
757 /* Scale the input X/Y offset to appear in proper position on the screen */
stretch(bool x,float size)758 inline float GuRenderer::stretch(bool x, float size) {
759 if (!_stretch)
760 return size;
761 return (x ? size * _stretchX : size * _stretchY);
762 }
763
guDrawVertices(Vertex * vertices)764 inline void GuRenderer::guDrawVertices(Vertex *vertices) {
765 DEBUG_ENTER_FUNC();
766
767 // This function shouldn't need changing. The '32' here refers to floating point vertices.
768 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices);
769 }
770
cacheInvalidate(void * pointer,uint32 size)771 void GuRenderer::cacheInvalidate(void *pointer, uint32 size) {
772 sceKernelDcacheWritebackInvalidateRange(pointer, size);
773 }
774