@ -18,10 +18,10 @@
# include "core/hw/gpu.h"
# include "video_core/command_processor.h"
# include "video_core/utils.h"
# include "video_core/video_core.h"
# include <video_core/color.h>
namespace GPU {
Regs g_regs ;
@ -116,24 +116,64 @@ inline void Write(u32 addr, const T data) {
u8 * source_pointer = Memory : : GetPointer ( Memory : : PhysicalToVirtualAddress ( config . GetPhysicalInputAddress ( ) ) ) ;
u8 * dest_pointer = Memory : : GetPointer ( Memory : : PhysicalToVirtualAddress ( config . GetPhysicalOutputAddress ( ) ) ) ;
// Cheap emulation of horizontal scaling: Just skip each second pixel of the
// input framebuffer. We keep track of this in the pixel_skip variable.
unsigned pixel_skip = ( config . scale_horizontally ! = 0 ) ? 2 : 1 ;
u32 output_width = config . output_width / pixel_skip ;
for ( u32 y = 0 ; y < config . output_height ; + + y ) {
// TODO: Why does the register seem to hold twice the framebuffer width?
unsigned horizontal_scale = ( config . scale_horizontally ! = 0 ) ? 2 : 1 ;
unsigned vertical_scale = ( config . scale_vertically ! = 0 ) ? 2 : 1 ;
u32 output_width = config . output_width / horizontal_scale ;
u32 output_height = config . output_height / vertical_scale ;
if ( config . raw_copy ) {
// Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions
// TODO(Subv): Verify if raw copies perform scaling
memcpy ( dest_pointer , source_pointer , config . output_width * config . output_height *
GPU : : Regs : : BytesPerPixel ( config . output_format ) ) ;
LOG_TRACE ( HW_GPU , " DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), flags 0x%08X, Raw copy " ,
config . output_height * output_width * GPU : : Regs : : BytesPerPixel ( config . output_format ) ,
config . GetPhysicalInputAddress ( ) , config . input_width . Value ( ) , config . input_height . Value ( ) ,
config . GetPhysicalOutputAddress ( ) , config . output_width . Value ( ) , config . output_height . Value ( ) ,
config . output_format . Value ( ) , config . flags ) ;
GSP_GPU : : SignalInterrupt ( GSP_GPU : : InterruptId : : PPF ) ;
break ;
}
// TODO(Subv): Blend the pixels when horizontal / vertical scaling is enabled,
// right now we're just skipping the extra pixels.
for ( u32 y = 0 ; y < output_height ; + + y ) {
for ( u32 x = 0 ; x < output_width ; + + x ) {
struct {
int r , g , b , a ;
} source_color = { 0 , 0 , 0 , 0 } ;
u32 scaled_x = x * horizontal_scale ;
u32 scaled_y = y * vertical_scale ;
u32 dst_bytes_per_pixel = GPU : : Regs : : BytesPerPixel ( config . output_format ) ;
u32 src_bytes_per_pixel = GPU : : Regs : : BytesPerPixel ( config . input_format ) ;
u32 src_offset ;
u32 dst_offset ;
if ( config . output_tiled ) {
// Interpret the input as linear and the output as tiled
u32 coarse_y = y & ~ 7 ;
u32 stride = output_width * dst_bytes_per_pixel ;
src_offset = ( scaled_x + scaled_y * config . input_width ) * src_bytes_per_pixel ;
dst_offset = VideoCore : : GetMortonOffset ( x , y , dst_bytes_per_pixel ) + coarse_y * stride ;
} else {
// Interpret the input as tiled and the output as linear
u32 coarse_y = scaled_y & ~ 7 ;
u32 stride = config . input_width * src_bytes_per_pixel ;
src_offset = VideoCore : : GetMortonOffset ( scaled_x , scaled_y , src_bytes_per_pixel ) + coarse_y * stride ;
dst_offset = ( x + y * output_width ) * dst_bytes_per_pixel ;
}
switch ( config . input_format ) {
case Regs : : PixelFormat : : RGBA8 :
{
u8 * srcptr = source_pointer + ( x * pixel_skip + y * config . input_width ) * 4 ;
u8 * srcptr = source_pointer + src_offset ;
source_color . r = srcptr [ 3 ] ; // red
source_color . g = srcptr [ 2 ] ; // green
source_color . b = srcptr [ 1 ] ; // blue
@ -143,7 +183,7 @@ inline void Write(u32 addr, const T data) {
case Regs : : PixelFormat : : RGB5A1 :
{
u16 srcval = * ( u16 * ) ( source_pointer + x * 4 * pixel_skip + y * config . input_width * 4 * pixel_skip ) ;
u16 srcval = * ( u16 * ) ( source_pointer + src_offset ) ;
source_color . r = Color : : Convert5To8 ( ( srcval > > 11 ) & 0x1F ) ; // red
source_color . g = Color : : Convert5To8 ( ( srcval > > 6 ) & 0x1F ) ; // green
source_color . b = Color : : Convert5To8 ( ( srcval > > 1 ) & 0x1F ) ; // blue
@ -153,7 +193,7 @@ inline void Write(u32 addr, const T data) {
case Regs : : PixelFormat : : RGBA4 :
{
u16 srcval = * ( u16 * ) ( source_pointer + x * 4 * pixel_skip + y * config . input_width * 4 * pixel_skip ) ;
u16 srcval = * ( u16 * ) ( source_pointer + src_offset ) ;
source_color . r = Color : : Convert4To8 ( ( srcval > > 12 ) & 0xF ) ; // red
source_color . g = Color : : Convert4To8 ( ( srcval > > 8 ) & 0xF ) ; // green
source_color . b = Color : : Convert4To8 ( ( srcval > > 4 ) & 0xF ) ; // blue
@ -169,7 +209,7 @@ inline void Write(u32 addr, const T data) {
switch ( config . output_format ) {
case Regs : : PixelFormat : : RGBA8 :
{
u8 * dstptr = dest_pointer + ( x * pixel_skip + y * config . output_width ) * 4 ;
u8 * dstptr = dest_pointer + dst_offset ;
dstptr [ 3 ] = source_color . r ;
dstptr [ 2 ] = source_color . g ;
dstptr [ 1 ] = source_color . b ;
@ -179,7 +219,7 @@ inline void Write(u32 addr, const T data) {
case Regs : : PixelFormat : : RGB8 :
{
u8 * dstptr = dest_pointer + ( x + y * output_width ) * 3 ;
u8 * dstptr = dest_pointer + dst_offset ;
dstptr [ 2 ] = source_color . r ; // red
dstptr [ 1 ] = source_color . g ; // green
dstptr [ 0 ] = source_color . b ; // blue
@ -188,7 +228,7 @@ inline void Write(u32 addr, const T data) {
case Regs : : PixelFormat : : RGB5A1 :
{
u16 * dstptr = ( u16 * ) ( dest_pointer + x * 2 + y * config . output_width * 2 ) ;
u16 * dstptr = ( u16 * ) ( dest_pointer + dst_offset ) ;
* dstptr = ( ( source_color . r > > 3 ) < < 11 ) | ( ( source_color . g > > 3 ) < < 6 )
| ( ( source_color . b > > 3 ) < < 1 ) | ( source_color . a > > 7 ) ;
break ;
@ -196,7 +236,7 @@ inline void Write(u32 addr, const T data) {
case Regs : : PixelFormat : : RGBA4 :
{
u16 * dstptr = ( u16 * ) ( dest_pointer + x * 2 + y * config . output_width * 2 ) ;
u16 * dstptr = ( u16 * ) ( dest_pointer + dst_offset ) ;
* dstptr = ( ( source_color . r > > 4 ) < < 12 ) | ( ( source_color . g > > 4 ) < < 8 )
| ( ( source_color . b > > 4 ) < < 4 ) | ( source_color . a > > 4 ) ;
break ;
@ -209,11 +249,11 @@ inline void Write(u32 addr, const T data) {
}
}
LOG_TRACE ( HW_GPU , " DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x " ,
config . output_height * output_width * 4 ,
config . GetPhysicalInputAddress ( ) , ( u32 ) config . input_width , ( u32 ) config . input_height ,
config . GetPhysicalOutputAddress ( ) , ( u32 ) output_width , ( u32 ) config . output_height ,
config . output_format . Value ( ) );
LOG_TRACE ( HW_GPU , " DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x , flags 0x%08X " ,
config . output_height * output_width * GPU : : Regs : : BytesPerPixel ( config . output_format ) ,
config . GetPhysicalInputAddress ( ) , config . input_width . Value ( ) , config . input_height . Value ( ) ,
config . GetPhysicalOutputAddress ( ) , output_width , output_height ,
config . output_format . Value ( ) , config . flags );
GSP_GPU : : SignalInterrupt ( GSP_GPU : : InterruptId : : PPF ) ;
}