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