From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/gfxdrivers/sh772x/sh7722_jpeglib.c | 1654 ++++++++++++++++++++ 1 file changed, 1654 insertions(+) create mode 100755 Source/DirectFB/gfxdrivers/sh772x/sh7722_jpeglib.c (limited to 'Source/DirectFB/gfxdrivers/sh772x/sh7722_jpeglib.c') diff --git a/Source/DirectFB/gfxdrivers/sh772x/sh7722_jpeglib.c b/Source/DirectFB/gfxdrivers/sh772x/sh7722_jpeglib.c new file mode 100755 index 0000000..6d88da8 --- /dev/null +++ b/Source/DirectFB/gfxdrivers/sh772x/sh7722_jpeglib.c @@ -0,0 +1,1654 @@ +#ifdef SH7722_DEBUG_JPEG +#define DIRECT_ENABLE_DEBUG +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef STANDALONE +#include "sh7722_jpeglib_standalone.h" +#else +#undef HAVE_STDLIB_H +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +#include +#include + +#include + +#include "sh7722_jpeglib.h" +#include "sh7722_regs.h" + + +D_DEBUG_DOMAIN( SH7722_JPEG, "SH7722/JPEG", "SH7722 JPEG Processing Unit" ); + +/**********************************************************************************************************************/ + +/* + * private data struct of SH7722_JPEG + */ +typedef struct { + int ref_count; + + int gfx_fd; + SH772xGfxSharedArea *gfx_shared; + + unsigned long jpeg_phys; + unsigned long jpeg_lb1; + unsigned long jpeg_lb2; + + volatile void *jpeg_virt; + + unsigned long mmio_phys; + volatile void *mmio_base; +} SH7722_JPEG_data; + +/**********************************************************************************************************************/ + +#if 1 +static inline u32 +SH7722_GETREG32( SH7722_JPEG_data *data, + u32 address ) +{ + SH772xRegister reg = { address, 0 }; + + if (ioctl( data->gfx_fd, SH772xGFX_IOCTL_GETREG32, ® ) < 0) + D_PERROR( "SH772xGFX_IOCTL_GETREG32( 0x%08x )\n", reg.address ); + + return reg.value; +} + +static inline void +SH7722_SETREG32( SH7722_JPEG_data *data, + u32 address, + u32 value ) +{ + SH772xRegister reg = { address, value }; + + if (ioctl( data->gfx_fd, SH772xGFX_IOCTL_SETREG32, ® ) < 0) + D_PERROR( "SH772xGFX_IOCTL_SETREG32( 0x%08x, 0x%08x )\n", reg.address, reg.value ); +} +#else +static inline u32 +SH7722_GETREG32( SH7722_JPEG_data *data, + u32 address ) +{ + D_ASSERT( address >= data->mmio_phys ); + D_ASSERT( address < (data->mmio_phys + data->mmio_length) ); + + return *(volatile u32*)(data->mmio_base + (address - data->mmio_phys)); +} + +static inline void +SH7722_SETREG32( SH7722_JPEG_data *data, + u32 address, + u32 value ) +{ + D_ASSERT( address >= data->mmio_phys ); + D_ASSERT( address < (data->mmio_phys + data->mmio_length) ); + + *(volatile u32*)(data->mmio_base + (address - data->mmio_phys)) = value; +} +#endif + +static inline int +coded_data_amount( SH7722_JPEG_data *data ) +{ + return (SH7722_GETREG32(data, JCDTCU) << 16) | (SH7722_GETREG32(data, JCDTCM) << 8) | SH7722_GETREG32(data, JCDTCD); +} + +/**********************************************************************************************************************/ + +static DirectResult +DecodeHW( SH7722_JPEG_data *data, + SH7722_JPEG_context *info, + const DFBRectangle *rect, + const DFBRegion *clip, + DFBSurfacePixelFormat format, + unsigned long phys, + int pitch, + unsigned int width, + unsigned int height ) +{ + DirectResult ret; + unsigned int len; + int i; + int cw, ch; + bool reload = false; + SH772xGfxSharedArea *shared = data->gfx_shared; + SH7722JPEG jpeg; + u32 vtrcr = 0; + u32 vswpout = 0; + DirectStream *stream = info->stream; + + D_ASSERT( data != NULL ); + DFB_RECTANGLE_ASSERT( rect ); + DFB_REGION_ASSERT( clip ); + + cw = clip->x2 - clip->x1 + 1; + ch = clip->y2 - clip->y1 + 1; + + if (cw < 1 || ch < 1) + return DR_INVAREA; + + D_DEBUG_AT( SH7722_JPEG, "%s( %p, 0x%08lx|%d [%dx%d] %s )\n", __FUNCTION__, + data, phys, pitch, info->width, info->height, + dfb_pixelformat_name(format) ); + + D_DEBUG_AT( SH7722_JPEG, " -> %d,%d - %4dx%4d [clip %d,%d - %4dx%4d]\n", + DFB_RECTANGLE_VALS( rect ), DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); + + /* + * Kernel based state machine + * + * Execution enters the kernel and only returns to user space for + * - end of decoding + * - error in decoding + * - reload requested + * + * TODO + * - finish clipping (maybe not all is possible without tricky code) + * - modify state machine to be used by Construct(), GetSurfaceDescription() and RenderTo() to avoid redundancy + * - check return code and length from GetData() + */ + + /* No cropping of top or left edge :( */ + if (clip->x1 > rect->x || clip->y1 > rect->y) { + D_UNIMPLEMENTED(); + return DR_UNIMPLEMENTED; + } + + /* Init VEU transformation control (format conversion). */ + if (!info->mode420) + vtrcr |= (1 << 14); + + switch (format) { + case DSPF_NV12: + vswpout = 0x70; + break; + + case DSPF_NV16: + vswpout = 0x70; + vtrcr |= (1 << 22); + break; + + case DSPF_RGB16: + vswpout = 0x60; + vtrcr |= (6 << 16) | 2; + break; + + case DSPF_RGB32: + vswpout = 0x40; + vtrcr |= (19 << 16) | 2; + break; + + case DSPF_RGB24: + vswpout = 0x70; + vtrcr |= (21 << 16) | 2; + break; + + default: + D_BUG( "unexpected format %s", dfb_pixelformat_name(format) ); + return DR_BUG; + } + + /* Calculate destination base address. */ + phys += DFB_BYTES_PER_LINE(format, rect->x) + rect->y * pitch; + jpeg.phys = phys; + + D_DEBUG_AT( SH7722_JPEG, " -> locking JPU...\n" ); + + if (ioctl( data->gfx_fd, SH7722GFX_IOCTL_LOCK_JPEG )) { + ret = errno2result( errno ); + D_PERROR( "SH7722/JPEG: Could not lock JPEG engine!\n" ); + return ret; + } + + D_DEBUG_AT( SH7722_JPEG, " -> loading...\n" ); + + /* Fill first reload buffer. */ + ret = direct_stream_read( stream, SH7722GFX_JPEG_RELOAD_SIZE, (void*) data->jpeg_virt, &len ); + if (ret) { + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + D_DERROR( ret, "SH7722/JPEG: Could not fill first reload buffer!\n" ); + return DR_IO; + } + + D_DEBUG_AT( SH7722_JPEG, " -> setting...\n" ); + + /* Initialize JPEG state. */ + jpeg.state = SH7722_JPEG_START; + jpeg.flags = 0; + jpeg.buffers = 1; + + /* Enable reload if buffer was filled completely (coded data length >= one reload buffer). */ + if (len == SH7722GFX_JPEG_RELOAD_SIZE) { + jpeg.flags |= SH7722_JPEG_FLAG_RELOAD; + + reload = true; + } + + /* Program JPU from RESET. */ + SH7722_SETREG32( data, JCCMD, JCCMD_RESET ); + SH7722_SETREG32( data, JCMOD, JCMOD_INPUT_CTRL | JCMOD_DSP_DECODE ); + SH7722_SETREG32( data, JIFCNT, JIFCNT_VJSEL_JPU ); + SH7722_SETREG32( data, JIFECNT, JIFECNT_SWAP_4321 ); + SH7722_SETREG32( data, JIFDSA1, data->jpeg_phys ); + SH7722_SETREG32( data, JIFDSA2, data->jpeg_phys + SH7722GFX_JPEG_RELOAD_SIZE ); + SH7722_SETREG32( data, JIFDDRSZ, len & 0x00FFFF00 ); + + if (info->width == cw && info->height == ch && rect->w == cw && rect->h == ch && + (( info->mode420 && format == DSPF_NV12) || + (!info->mode420 && format == DSPF_NV16))) + { + /* Setup JPU for decoding in frame mode (directly to surface). */ + SH7722_SETREG32( data, JINTE, JINTS_INS5_ERROR | JINTS_INS6_DONE | + (reload ? JINTS_INS14_RELOAD : 0) ); + SH7722_SETREG32( data, JIFDCNT, JIFDCNT_SWAP_4321 | (reload ? JIFDCNT_RELOAD_ENABLE : 0) ); + + SH7722_SETREG32( data, JIFDDYA1, phys ); + SH7722_SETREG32( data, JIFDDCA1, phys + pitch * height ); + SH7722_SETREG32( data, JIFDDMW, pitch ); + } + else { + jpeg.flags |= SH7722_JPEG_FLAG_CONVERT; + + /* Setup JPU for decoding in line buffer mode. */ + SH7722_SETREG32( data, JINTE, JINTS_INS5_ERROR | JINTS_INS6_DONE | + JINTS_INS11_LINEBUF0 | JINTS_INS12_LINEBUF1 | + (reload ? JINTS_INS14_RELOAD : 0) ); + SH7722_SETREG32( data, JIFDCNT, JIFDCNT_LINEBUF_MODE | (SH7722GFX_JPEG_LINEBUFFER_HEIGHT << 16) | + JIFDCNT_SWAP_4321 | (reload ? JIFDCNT_RELOAD_ENABLE : 0) ); + + SH7722_SETREG32( data, JIFDDYA1, data->jpeg_lb1 ); + SH7722_SETREG32( data, JIFDDCA1, data->jpeg_lb1 + SH7722GFX_JPEG_LINEBUFFER_SIZE_Y ); + SH7722_SETREG32( data, JIFDDYA2, data->jpeg_lb2 ); + SH7722_SETREG32( data, JIFDDCA2, data->jpeg_lb2 + SH7722GFX_JPEG_LINEBUFFER_SIZE_Y ); + SH7722_SETREG32( data, JIFDDMW, SH7722GFX_JPEG_LINEBUFFER_PITCH ); + + /* Setup VEU for conversion/scaling (from line buffer to surface). */ + SH7722_SETREG32( data, VEU_VBSRR, 0x00000100 ); + SH7722_SETREG32( data, VEU_VESTR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VESWR, SH7722GFX_JPEG_LINEBUFFER_PITCH ); + SH7722_SETREG32( data, VEU_VESSR, (info->height << 16) | info->width ); + SH7722_SETREG32( data, VEU_VBSSR, 16 ); + SH7722_SETREG32( data, VEU_VEDWR, pitch ); + SH7722_SETREG32( data, VEU_VDAYR, phys ); + SH7722_SETREG32( data, VEU_VDACR, phys + pitch * height ); + SH7722_SETREG32( data, VEU_VTRCR, vtrcr ); + + SH7722_SETREG32( data, VEU_VRFCR, (((info->height << 12) / rect->h) << 16) | + ((info->width << 12) / rect->w) ); + SH7722_SETREG32( data, VEU_VRFSR, (ch << 16) | cw ); + + SH7722_SETREG32( data, VEU_VENHR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VFMCR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VAPCR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VSWPR, 0x00000007 | vswpout ); + SH7722_SETREG32( data, VEU_VEIER, 0x00000101 ); + } + + D_DEBUG_AT( SH7722_JPEG, " -> starting...\n" ); + + /* Clear interrupts in shared flags. */ + shared->jpeg_ints = 0; + + /* State machine. */ + while (true) { + /* Run the state machine. */ + if (ioctl( data->gfx_fd, SH7722GFX_IOCTL_RUN_JPEG, &jpeg ) < 0) { + ret = errno2result( errno ); + + D_PERROR( "SH7722/JPEG: SH7722GFX_IOCTL_RUN_JPEG failed!\n" ); + break; + } + + D_ASSERT( jpeg.state != SH7722_JPEG_START ); + + /* Handle end (or error). */ + if (jpeg.state == SH7722_JPEG_END) { + if (jpeg.error) { + D_ERROR( "SH7722/JPEG: ERROR 0x%x!\n", jpeg.error ); + ret = DR_IO; + } + + break; + } + + /* Check for reload requests. */ + for (i=1; i<=2; i++) { + if (jpeg.buffers & i) { + if (jpeg.flags & SH7722_JPEG_FLAG_RELOAD) { + D_ASSERT( reload ); + + ret = direct_stream_read( stream, SH7722GFX_JPEG_RELOAD_SIZE, + (void*) data->jpeg_virt + + SH7722GFX_JPEG_RELOAD_SIZE * (i-1), &len ); + if (ret) { + D_DERROR( ret, "SH7722/JPEG: Could not refill %s reload buffer!\n", + i == 1 ? "first" : "second" ); + jpeg.buffers &= ~i; + jpeg.flags &= ~SH7722_JPEG_FLAG_RELOAD; + } + else if (len < SH7722GFX_JPEG_RELOAD_SIZE) + jpeg.flags &= ~SH7722_JPEG_FLAG_RELOAD; + } + else + jpeg.buffers &= ~i; + } + } + } + + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + + return ret; +} + +static int calculate_scaling( int input, int output ) +{ + int frac = 0; + int mant = 0; + + if( input == output ) { /* no scaling, done */ + return 0; + } + + mant = input / output; + frac = ((input * 4096 / output) & ~7) - mant * 4096; + + if( input < output ) { /* upscaling */ + if( input*8 < output ) /* out-of-range */ + return -1; + + while( output > 1 + (int)((input-1)*4096/frac) ) { + frac -= 8; + } + } + else { /* downscaling */ + int a,size,pmant; + + if( output*16 < input ) /* out-of-range */ + return -1; + + while(1) { + pmant = "1122333344444444"[mant] - '0'; + a = mant * 4096 + frac; + size = (2*(input-1)*pmant)/(2*pmant); + size = (((size-1) * 4096 * pmant) + a) / a; + + if( output <= size ) + break; + + if( frac ) + frac -= 8; + else { + mant--; + frac = 0xff8; + } + } + } + + return (mant << 12) + frac; +} + +static DirectResult +EncodeHW( SH7722_JPEG_data *data, + const char *filename, + const DFBRectangle *rect, + DFBSurfacePixelFormat format, + unsigned long phys, + int pitch, + unsigned int width, + unsigned int height, + unsigned long tmpphys ) +{ + DirectResult ret; + int i, fd; + int written = 0; + SH772xGfxSharedArea *shared = data->gfx_shared; + u32 vtrcr = 0; + u32 vswpin = 0; + bool mode420 = false; + SH7722JPEG jpeg; + + int horizontalscaling = 0; + int verticalscaling = 0; + + int clipwidth, clipheight; + DFBRectangle cliprect; + + /* VEU has cliprequirement of 4 bytes, input and output must be 4 pixel aligned. + * We have to be careful with scaling: take clipped output and input */ + + cliprect.h = (rect->h + 0x3) & ~0x3; + cliprect.w = (rect->w + 0x3) & ~0x3; + clipheight = (height + 0x3) & ~0x3; + clipwidth = (width + 0x3) & ~0x3; + + D_ASSERT( data != NULL ); + DFB_RECTANGLE_ASSERT( rect ); + + D_DEBUG_AT( SH7722_JPEG, "%s( %p, 0x%08lx|%d [%dx%d] %s )\n", __FUNCTION__, + data, phys, pitch, width, height, + dfb_pixelformat_name(format) ); + + D_DEBUG_AT( SH7722_JPEG, " -> %d,%d - %4dx%4d (at %lx)\n", + DFB_RECTANGLE_VALS( rect ), tmpphys ); + + /* JPU input is 16x16 to 2560x1920 */ + if (width < 16 || width > 2560 || height < 16 || height > 1920) + return DR_INVAREA; + + if (rect->w < 1 || rect->h < 1) + return DR_INVAREA; + + horizontalscaling = calculate_scaling( cliprect.w, clipwidth ); + verticalscaling = calculate_scaling( cliprect.h, clipheight ); + if( !tmpphys ) { + /* we don't have enough memory, so we do it in 16 pixel steps */ + int h = ((rect->h * SH7722GFX_JPEG_LINEBUFFER_HEIGHT / height) + 0x3) & ~0x3; + verticalscaling = calculate_scaling( h, SH7722GFX_JPEG_LINEBUFFER_HEIGHT ); + } + + /* scaling out-of-range? */ + if( horizontalscaling == -1 || verticalscaling == -1 ) + return DR_INVAREA; + + /* + * Kernel based state machine + * + * Execution enters the kernel and only returns to user space for + * - end of encoding + * - error in encoding + * - buffer loaded + * + * TODO + * - finish clipping (maybe not all is possible without tricky code) + */ + + /* Init VEU transformation control (format conversion). */ + if (format == DSPF_NV12) + mode420 = true; + else + vtrcr |= (1 << 22); + + switch (format) { + case DSPF_NV12: + vswpin = 0x07; + break; + + case DSPF_NV16: + vswpin = 0x07; + vtrcr |= (1 << 14); + break; + + case DSPF_RGB16: + vswpin = 0x06; + vtrcr |= (3 << 8) | 3; + break; + + case DSPF_RGB32: + vswpin = 0x04; + vtrcr |= (0 << 8) | 3; + break; + + case DSPF_RGB24: + vswpin = 0x07; + vtrcr |= (2 << 8) | 3; + break; + + default: + D_BUG( "unexpected format %s", dfb_pixelformat_name(format) ); + return DR_BUG; + } + + /* Calculate source base address. */ + /* TODO: NV12 input with offset. Colour will be off.. */ + phys += DFB_BYTES_PER_LINE(format, rect->x) + rect->y * pitch; + jpeg.phys = phys; + + D_DEBUG_AT( SH7722_JPEG, " -> locking JPU...\n" ); + + if (ioctl( data->gfx_fd, SH7722GFX_IOCTL_LOCK_JPEG )) { + ret = errno2result( errno ); + D_PERROR( "SH7722/JPEG: Could not lock JPEG engine!\n" ); + return ret; + } + + D_DEBUG_AT( SH7722_JPEG, " -> opening '%s' for writing...\n", filename ); + + fd = open( filename, O_WRONLY | O_CREAT | O_TRUNC, 0644 ); + if (fd < 0) { + ret = errno2result( errno ); + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + D_PERROR( "SH7722/JPEG: Failed to open '%s' for writing!\n", filename ); + return ret; + } + + D_DEBUG_AT( SH7722_JPEG, " -> setting...\n" ); + + /* Initialize JPEG state. */ + jpeg.state = SH7722_JPEG_START; + jpeg.flags = SH7722_JPEG_FLAG_ENCODE; + jpeg.buffers = 3; + + /* Always enable reload mode. */ + jpeg.flags |= SH7722_JPEG_FLAG_RELOAD; + + /* Program JPU from RESET. */ + SH7722_SETREG32( data, JCCMD, JCCMD_RESET ); + SH7722_SETREG32( data, JCMOD, JCMOD_INPUT_CTRL | JCMOD_DSP_ENCODE | (mode420 ? 2 : 1) ); + + SH7722_SETREG32( data, JCQTN, 0x14 ); + SH7722_SETREG32( data, JCHTN, 0x3C ); + SH7722_SETREG32( data, JCDRIU, 0x02 ); + SH7722_SETREG32( data, JCDRID, 0x00 ); + SH7722_SETREG32( data, JCHSZU, width >> 8 ); + SH7722_SETREG32( data, JCHSZD, width & 0xff ); + SH7722_SETREG32( data, JCVSZU, height >> 8 ); + SH7722_SETREG32( data, JCVSZD, height & 0xff ); + SH7722_SETREG32( data, JIFCNT, JIFCNT_VJSEL_JPU ); + SH7722_SETREG32( data, JIFDCNT, JIFDCNT_SWAP_4321 ); + SH7722_SETREG32( data, JIFEDA1, data->jpeg_phys ); + SH7722_SETREG32( data, JIFEDA2, data->jpeg_phys + SH7722GFX_JPEG_RELOAD_SIZE ); + SH7722_SETREG32( data, JIFEDRSZ, SH7722GFX_JPEG_RELOAD_SIZE ); + SH7722_SETREG32( data, JIFESHSZ, clipwidth ); + SH7722_SETREG32( data, JIFESVSZ, clipheight ); + + if (width == rect->w && height == rect->h && (format == DSPF_NV12 || format == DSPF_NV16)) + { + D_DEBUG_AT( SH7722_JPEG, " -> no VEU needed\n" ); + + /* no scaling, and supported format - so no VEU needed */ + /* Setup JPU for encoding in frame mode (directly from surface). */ + SH7722_SETREG32( data, JINTE, JINTS_INS10_XFER_DONE | JINTS_INS13_LOADED ); + SH7722_SETREG32( data, JIFECNT, JIFECNT_SWAP_4321 | JIFECNT_RELOAD_ENABLE | (mode420 ? 1 : 0) ); + + SH7722_SETREG32( data, JIFESYA1, phys ); + SH7722_SETREG32( data, JIFESCA1, phys + pitch * height ); + SH7722_SETREG32( data, JIFESMW, pitch ); + } + else { + /* Setup JPU for encoding in line buffer mode. */ + jpeg.flags |= SH7722_JPEG_FLAG_CONVERT; + jpeg.height = height; + jpeg.inputheight = rect->h; + + SH7722_SETREG32( data, JINTE, JINTS_INS11_LINEBUF0 | JINTS_INS12_LINEBUF1 | + JINTS_INS10_XFER_DONE | JINTS_INS13_LOADED ); + + if( tmpphys ) { + /* we have enough memory, so we just read one big "line" */ + SH7722_SETREG32( data, JIFECNT, JIFECNT_LINEBUF_MODE | (height << 16) | + JIFECNT_SWAP_4321 | JIFECNT_RELOAD_ENABLE | (mode420 ? 1 : 0) ); + SH7722_SETREG32( data, JIFESYA1, tmpphys ); + SH7722_SETREG32( data, JIFESCA1, tmpphys + clipwidth * height ); /* Y is 8bpp */ + SH7722_SETREG32( data, JIFESMW, clipwidth ); + } + else { + SH7722_SETREG32( data, JIFECNT, JIFECNT_LINEBUF_MODE | (SH7722GFX_JPEG_LINEBUFFER_HEIGHT << 16) | + JIFECNT_SWAP_4321 | JIFECNT_RELOAD_ENABLE | (mode420 ? 1 : 0) ); + + SH7722_SETREG32( data, JIFESYA1, data->jpeg_lb1 ); + SH7722_SETREG32( data, JIFESCA1, data->jpeg_lb1 + SH7722GFX_JPEG_LINEBUFFER_SIZE_Y ); + SH7722_SETREG32( data, JIFESMW, SH7722GFX_JPEG_LINEBUFFER_PITCH ); + } + SH7722_SETREG32( data, JIFESYA2, data->jpeg_lb2 ); + SH7722_SETREG32( data, JIFESCA2, data->jpeg_lb2 + SH7722GFX_JPEG_LINEBUFFER_SIZE_Y ); + + /* we will not use the VEU in burst mode since we cannot program the + * destination addresses intermediately in line mode. */ + SH7722_SETREG32( data, VEU_VBSRR, 0x00000100 ); + SH7722_SETREG32( data, VEU_VESTR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VSAYR, phys ); + SH7722_SETREG32( data, VEU_VSACR, phys + pitch * height ); + SH7722_SETREG32( data, VEU_VESWR, pitch ); + + if( tmpphys ) { + SH7722_SETREG32( data, VEU_VESSR, (cliprect.h << 16) | cliprect.w ); + SH7722_SETREG32( data, VEU_VEDWR, clipwidth ); + SH7722_SETREG32( data, VEU_VDAYR, tmpphys ); + SH7722_SETREG32( data, VEU_VDACR, tmpphys + clipwidth * height ); + SH7722_SETREG32( data, VEU_VRFSR, (clipheight << 16) | clipwidth ); + } + else { + int h = ((rect->h * SH7722GFX_JPEG_LINEBUFFER_HEIGHT / height) + 0x3) & ~0x3; + SH7722_SETREG32( data, VEU_VESSR, (h << 16) | cliprect.w ); + SH7722_SETREG32( data, VEU_VEDWR, SH7722GFX_JPEG_LINEBUFFER_PITCH ); + SH7722_SETREG32( data, VEU_VDAYR, data->jpeg_lb1 ); + SH7722_SETREG32( data, VEU_VDACR, data->jpeg_lb1 + SH7722GFX_JPEG_LINEBUFFER_SIZE_Y ); + SH7722_SETREG32( data, VEU_VRFSR, (SH7722GFX_JPEG_LINEBUFFER_HEIGHT << 16) | clipwidth ); + } + SH7722_SETREG32( data, VEU_VRFCR, (verticalscaling << 16) | horizontalscaling ); + SH7722_SETREG32( data, VEU_VTRCR, vtrcr ); + SH7722_SETREG32( data, VEU_VENHR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VFMCR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VAPCR, 0x00000000 ); + SH7722_SETREG32( data, VEU_VSWPR, 0x00000070 | vswpin ); + SH7722_SETREG32( data, VEU_VEIER, 0x00000101 ); + } + + /* Init quantization tables. */ + SH7722_SETREG32( data, JCQTBL0( 0), 0x100B0B0E ); + SH7722_SETREG32( data, JCQTBL0( 1), 0x0C0A100E ); + SH7722_SETREG32( data, JCQTBL0( 2), 0x0D0E1211 ); + SH7722_SETREG32( data, JCQTBL0( 3), 0x10131828 ); + SH7722_SETREG32( data, JCQTBL0( 4), 0x1A181616 ); + SH7722_SETREG32( data, JCQTBL0( 5), 0x18312325 ); + SH7722_SETREG32( data, JCQTBL0( 6), 0x1D283A33 ); + SH7722_SETREG32( data, JCQTBL0( 7), 0x3D3C3933 ); + SH7722_SETREG32( data, JCQTBL0( 8), 0x38374048 ); + SH7722_SETREG32( data, JCQTBL0( 9), 0x5C4E4044 ); + SH7722_SETREG32( data, JCQTBL0(10), 0x57453738 ); + SH7722_SETREG32( data, JCQTBL0(11), 0x506D5157 ); + SH7722_SETREG32( data, JCQTBL0(12), 0x5F626768 ); + SH7722_SETREG32( data, JCQTBL0(13), 0x673E4D71 ); + SH7722_SETREG32( data, JCQTBL0(14), 0x79706478 ); + SH7722_SETREG32( data, JCQTBL0(15), 0x5C656763 ); + + SH7722_SETREG32( data, JCQTBL1( 0), 0x11121218 ); + SH7722_SETREG32( data, JCQTBL1( 1), 0x15182F1A ); + SH7722_SETREG32( data, JCQTBL1( 2), 0x1A2F6342 ); + SH7722_SETREG32( data, JCQTBL1( 3), 0x38426363 ); + SH7722_SETREG32( data, JCQTBL1( 4), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1( 5), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1( 6), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1( 7), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1( 8), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1( 9), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1(10), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1(11), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1(12), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1(13), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1(14), 0x63636363 ); + SH7722_SETREG32( data, JCQTBL1(15), 0x63636363 ); + + /* Init huffman tables. */ + SH7722_SETREG32( data, JCHTBD0(0), 0x00010501 ); + SH7722_SETREG32( data, JCHTBD0(1), 0x01010101 ); + SH7722_SETREG32( data, JCHTBD0(2), 0x01000000 ); + SH7722_SETREG32( data, JCHTBD0(3), 0x00000000 ); + SH7722_SETREG32( data, JCHTBD0(4), 0x00010203 ); + SH7722_SETREG32( data, JCHTBD0(5), 0x04050607 ); + SH7722_SETREG32( data, JCHTBD0(6), 0x08090A0B ); + + SH7722_SETREG32( data, JCHTBD1(0), 0x00030101 ); + SH7722_SETREG32( data, JCHTBD1(1), 0x01010101 ); + SH7722_SETREG32( data, JCHTBD1(2), 0x01010100 ); + SH7722_SETREG32( data, JCHTBD1(3), 0x00000000 ); + SH7722_SETREG32( data, JCHTBD1(4), 0x00010203 ); + SH7722_SETREG32( data, JCHTBD1(5), 0x04050607 ); + SH7722_SETREG32( data, JCHTBD1(6), 0x08090A0B ); + + SH7722_SETREG32( data, JCHTBA0( 0), 0x00020103 ); + SH7722_SETREG32( data, JCHTBA0( 1), 0x03020403 ); + SH7722_SETREG32( data, JCHTBA0( 2), 0x05050404 ); + SH7722_SETREG32( data, JCHTBA0( 3), 0x0000017D ); + SH7722_SETREG32( data, JCHTBA0( 4), 0x01020300 ); + SH7722_SETREG32( data, JCHTBA0( 5), 0x04110512 ); + SH7722_SETREG32( data, JCHTBA0( 6), 0x21314106 ); + SH7722_SETREG32( data, JCHTBA0( 7), 0x13516107 ); + SH7722_SETREG32( data, JCHTBA0( 8), 0x22711432 ); + SH7722_SETREG32( data, JCHTBA0( 9), 0x8191A108 ); + SH7722_SETREG32( data, JCHTBA0(10), 0x2342B1C1 ); + SH7722_SETREG32( data, JCHTBA0(11), 0x1552D1F0 ); + SH7722_SETREG32( data, JCHTBA0(12), 0x24336272 ); + SH7722_SETREG32( data, JCHTBA0(13), 0x82090A16 ); + SH7722_SETREG32( data, JCHTBA0(14), 0x1718191A ); + SH7722_SETREG32( data, JCHTBA0(15), 0x25262728 ); + SH7722_SETREG32( data, JCHTBA0(16), 0x292A3435 ); + SH7722_SETREG32( data, JCHTBA0(17), 0x36373839 ); + SH7722_SETREG32( data, JCHTBA0(18), 0x3A434445 ); + SH7722_SETREG32( data, JCHTBA0(19), 0x46474849 ); + SH7722_SETREG32( data, JCHTBA0(20), 0x4A535455 ); + SH7722_SETREG32( data, JCHTBA0(21), 0x56575859 ); + SH7722_SETREG32( data, JCHTBA0(22), 0x5A636465 ); + SH7722_SETREG32( data, JCHTBA0(23), 0x66676869 ); + SH7722_SETREG32( data, JCHTBA0(24), 0x6A737475 ); + SH7722_SETREG32( data, JCHTBA0(25), 0x76777879 ); + SH7722_SETREG32( data, JCHTBA0(26), 0x7A838485 ); + SH7722_SETREG32( data, JCHTBA0(27), 0x86878889 ); + SH7722_SETREG32( data, JCHTBA0(28), 0x8A929394 ); + SH7722_SETREG32( data, JCHTBA0(29), 0x95969798 ); + SH7722_SETREG32( data, JCHTBA0(30), 0x999AA2A3 ); + SH7722_SETREG32( data, JCHTBA0(31), 0xA4A5A6A7 ); + SH7722_SETREG32( data, JCHTBA0(32), 0xA8A9AAB2 ); + SH7722_SETREG32( data, JCHTBA0(33), 0xB3B4B5B6 ); + SH7722_SETREG32( data, JCHTBA0(34), 0xB7B8B9BA ); + SH7722_SETREG32( data, JCHTBA0(35), 0xC2C3C4C5 ); + SH7722_SETREG32( data, JCHTBA0(36), 0xC6C7C8C9 ); + SH7722_SETREG32( data, JCHTBA0(37), 0xCAD2D3D4 ); + SH7722_SETREG32( data, JCHTBA0(38), 0xD5D6D7D8 ); + SH7722_SETREG32( data, JCHTBA0(39), 0xD9DAE1E2 ); + SH7722_SETREG32( data, JCHTBA0(40), 0xE3E4E5E6 ); + SH7722_SETREG32( data, JCHTBA0(41), 0xE7E8E9EA ); + SH7722_SETREG32( data, JCHTBA0(42), 0xF1F2F3F4 ); + SH7722_SETREG32( data, JCHTBA0(43), 0xF5F6F7F8 ); + SH7722_SETREG32( data, JCHTBA0(44), 0xF9FA0000 ); + + SH7722_SETREG32( data, JCHTBA1( 0), 0x00020102 ); + SH7722_SETREG32( data, JCHTBA1( 1), 0x04040304 ); + SH7722_SETREG32( data, JCHTBA1( 2), 0x07050404 ); + SH7722_SETREG32( data, JCHTBA1( 3), 0x00010277 ); + SH7722_SETREG32( data, JCHTBA1( 4), 0x00010203 ); + SH7722_SETREG32( data, JCHTBA1( 5), 0x11040521 ); + SH7722_SETREG32( data, JCHTBA1( 6), 0x31061241 ); + SH7722_SETREG32( data, JCHTBA1( 7), 0x51076171 ); + SH7722_SETREG32( data, JCHTBA1( 8), 0x13223281 ); + SH7722_SETREG32( data, JCHTBA1( 9), 0x08144291 ); + SH7722_SETREG32( data, JCHTBA1(10), 0xA1B1C109 ); + SH7722_SETREG32( data, JCHTBA1(11), 0x233352F0 ); + SH7722_SETREG32( data, JCHTBA1(12), 0x156272D1 ); + SH7722_SETREG32( data, JCHTBA1(13), 0x0A162434 ); + SH7722_SETREG32( data, JCHTBA1(14), 0xE125F117 ); + SH7722_SETREG32( data, JCHTBA1(15), 0x18191A26 ); + SH7722_SETREG32( data, JCHTBA1(16), 0x2728292A ); + SH7722_SETREG32( data, JCHTBA1(17), 0x35363738 ); + SH7722_SETREG32( data, JCHTBA1(18), 0x393A4344 ); + SH7722_SETREG32( data, JCHTBA1(19), 0x45464748 ); + SH7722_SETREG32( data, JCHTBA1(20), 0x494A5354 ); + SH7722_SETREG32( data, JCHTBA1(21), 0x55565758 ); + SH7722_SETREG32( data, JCHTBA1(22), 0x595A6364 ); + SH7722_SETREG32( data, JCHTBA1(23), 0x65666768 ); + SH7722_SETREG32( data, JCHTBA1(24), 0x696A7374 ); + SH7722_SETREG32( data, JCHTBA1(25), 0x75767778 ); + SH7722_SETREG32( data, JCHTBA1(26), 0x797A8283 ); + SH7722_SETREG32( data, JCHTBA1(27), 0x84858687 ); + SH7722_SETREG32( data, JCHTBA1(28), 0x88898A92 ); + SH7722_SETREG32( data, JCHTBA1(29), 0x93949596 ); + SH7722_SETREG32( data, JCHTBA1(30), 0x9798999A ); + SH7722_SETREG32( data, JCHTBA1(31), 0xA2A3A4A5 ); + SH7722_SETREG32( data, JCHTBA1(32), 0xA6A7A8A9 ); + SH7722_SETREG32( data, JCHTBA1(33), 0xAAB2B3B4 ); + SH7722_SETREG32( data, JCHTBA1(34), 0xB5B6B7B8 ); + SH7722_SETREG32( data, JCHTBA1(35), 0xB9BAC2C3 ); + SH7722_SETREG32( data, JCHTBA1(36), 0xC4C5C6C7 ); + SH7722_SETREG32( data, JCHTBA1(37), 0xC8C9CAD2 ); + SH7722_SETREG32( data, JCHTBA1(38), 0xD3D4D5D6 ); + SH7722_SETREG32( data, JCHTBA1(39), 0xD7D8D9DA ); + SH7722_SETREG32( data, JCHTBA1(40), 0xE2E3E4E5 ); + SH7722_SETREG32( data, JCHTBA1(41), 0xE6E7E8E9 ); + SH7722_SETREG32( data, JCHTBA1(42), 0xEAF2F3F4 ); + SH7722_SETREG32( data, JCHTBA1(43), 0xF5F6F7F8 ); + SH7722_SETREG32( data, JCHTBA1(44), 0xF9FA0000 ); + + /* Clear interrupts in shared flags. */ + shared->jpeg_ints = 0; + + D_DEBUG_AT( SH7722_JPEG, " -> starting...\n" ); + + /* State machine. */ + while (true) { + /* Run the state machine. */ + if (ioctl( data->gfx_fd, SH7722GFX_IOCTL_RUN_JPEG, &jpeg ) < 0) { + ret = errno2result( errno ); + + D_PERROR( "SH7722/JPEG: SH7722GFX_IOCTL_RUN_JPEG failed!\n" ); + break; + } + + D_ASSERT( jpeg.state != SH7722_JPEG_START ); + + /* Check for loaded buffers. */ + for (i=1; i<=2; i++) { + if (jpeg.buffers & i) { + int amount = coded_data_amount( data ) - written; + + if (amount > SH7722GFX_JPEG_RELOAD_SIZE) + amount = SH7722GFX_JPEG_RELOAD_SIZE; + + D_INFO( "SH7722/JPEG: Coded data amount: + %5d (buffer %d)\n", amount, i ); + + written += write( fd, (void*) data->jpeg_virt + SH7722GFX_JPEG_RELOAD_SIZE * (i-1), amount ); + } + } + + /* Handle end (or error). */ + if (jpeg.state == SH7722_JPEG_END) { + if (jpeg.error) { + D_ERROR( "SH7722/JPEG: ERROR 0x%x!\n", jpeg.error ); + ret = DR_IO; + } + + break; + } + } + + D_INFO( "SH7722/JPEG: Coded data amount: = %5d (written: %d, buffers: %d)\n", + coded_data_amount( data ), written, jpeg.buffers ); + + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + + close( fd ); + + return DR_OK; +} + +#if 0 +static DirectResult +DecodeHeader( SH7722_JPEG_data *data, + DirectStream *stream, + SH7722_JPEG_context *info ) +{ + DirectResult ret; + unsigned int len; + SH772xGfxSharedArea *shared; + + D_DEBUG_AT( SH7722_JPEG, "%s( %p )\n", __FUNCTION__, data ); + + D_ASSERT( data != NULL ); + + shared = data->gfx_shared; + + /* + * Do minimal stuff to decode the image header, serving as a good probe mechanism as well. + */ + + D_DEBUG_AT( SH7722_JPEG, " -> locking JPU...\n" ); + + if (ioctl( data->gfx_fd, SH7722GFX_IOCTL_LOCK_JPEG )) { + ret = errno2result( errno ); + D_PERROR( "SH7722/JPEG: Could not lock JPEG engine!\n" ); + return ret; + } + + D_DEBUG_AT( SH7722_JPEG, " -> loading 32k...\n" ); + + /* Prefill reload buffer with 32k. */ + ret = direct_stream_peek( stream, 32*1024, 0, (void*) data->jpeg_virt, &len ); + if (ret) { + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + D_DEBUG_AT( SH7722_JPEG, " -> ERROR from PeekData(): %s\n", DirectResultString(ret) ); + return DR_IO; + } + + D_DEBUG_AT( SH7722_JPEG, " -> %u bytes loaded, setting...\n", len ); + + /* Program JPU from RESET. */ + SH7722_SETREG32( data, JCCMD, JCCMD_RESET ); + SH7722_SETREG32( data, JCMOD, JCMOD_INPUT_CTRL | JCMOD_DSP_DECODE ); + SH7722_SETREG32( data, JINTE, JINTS_INS3_HEADER | JINTS_INS5_ERROR ); + SH7722_SETREG32( data, JIFCNT, JIFCNT_VJSEL_JPU ); + SH7722_SETREG32( data, JIFECNT, JIFECNT_SWAP_4321 ); + SH7722_SETREG32( data, JIFDCNT, JIFDCNT_SWAP_4321 ); + SH7722_SETREG32( data, JIFDSA1, data->jpeg_phys ); + SH7722_SETREG32( data, JIFDDRSZ, len ); + + D_DEBUG_AT( SH7722_JPEG, " -> starting...\n" ); + + /* Clear interrupts in shared flags. */ + shared->jpeg_ints = 0; + + /* Start decoder and begin reading from buffer. */ + SH7722_SETREG32( data, JCCMD, JCCMD_START ); + + /* Stall machine. */ + while (true) { + /* Check for new interrupts in shared flags... */ + u32 ints = shared->jpeg_ints; + if (ints) { + /* ...and clear them (FIXME: race condition in case of multiple IRQs per command!). */ + shared->jpeg_ints &= ~ints; + + D_DEBUG_AT( SH7722_JPEG, " -> JCSTS 0x%08x, JINTS 0x%08x\n", SH7722_GETREG32( data, JCSTS ), ints ); + + /* Check for errors! */ + if (ints & JINTS_INS5_ERROR) { + D_ERROR( "SH7722/JPEG: ERROR 0x%x!\n", SH7722_GETREG32( data, JCDERR ) ); + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + return DR_IO; + } + + /* Check for header interception... */ + if (ints & JINTS_INS3_HEADER) { + /* ...remember image information... */ + info->width = SH7722_GETREG32( data, JIFDDHSZ ); + info->height = SH7722_GETREG32( data, JIFDDVSZ ); + info->mode420 = (SH7722_GETREG32( data, JCMOD ) & 2) ? true : false; + + D_DEBUG_AT( SH7722_JPEG, " -> %dx%d (4:2:%c)\n", + info->width, info->height, info->mode420 ? '0' : '2' ); + + break; + } + } + else { + D_DEBUG_AT( SH7722_JPEG, " -> waiting...\n" ); + + /* ...otherwise wait for the arrival of new interrupt(s). */ + if (ioctl( data->gfx_fd, SH7722GFX_IOCTL_WAIT_JPEG ) < 0) { + D_PERROR( "SH7722/JPEG: Waiting for IRQ failed! (ints: 0x%x - JINTS 0x%x, JCSTS 0x%x)\n", + ints, SH7722_GETREG32( data, JINTS ), SH7722_GETREG32( data, JCSTS ) ); + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + return DR_FAILURE; + } + } + } + + ioctl( data->gfx_fd, SH7722GFX_IOCTL_UNLOCK_JPEG ); + + if (info->width < 16 || info->width > 2560) + return DR_UNSUPPORTED; + + if (info->height < 16 || info->height > 1920) + return DR_UNSUPPORTED; + + return DR_OK; +} +#endif + +/**********************************************************************************************************************/ + +static void write_rgb_span( u8 *src, void *dst, int len, DFBSurfacePixelFormat format ) +{ + int i; + + switch (format) { + case DSPF_RGB332: + for (i = 0; i < len; i++) + ((u8*)dst)[i] = PIXEL_RGB332( src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_ARGB1555: + for (i = 0; i < len; i++) + ((u16*)dst)[i] = PIXEL_ARGB1555( 0xff, src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_ARGB2554: + for (i = 0; i < len; i++) + ((u16*)dst)[i] = PIXEL_ARGB2554( 0xff, src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_ARGB4444: + for (i = 0; i < len; i++) + ((u16*)dst)[i] = PIXEL_ARGB4444( 0xff, src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_RGB16: + for (i = 0; i < len; i++) + ((u16*)dst)[i] = PIXEL_RGB16( src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_RGB24: + direct_memcpy( dst, src, len*3 ); + break; + + case DSPF_RGB32: + for (i = 0; i < len; i++) + ((u32*)dst)[i] = PIXEL_RGB32( src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_ARGB: + for (i = 0; i < len; i++) + ((u32*)dst)[i] = PIXEL_ARGB( 0xff, src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_AiRGB: + for (i = 0; i < len; i++) + ((u32*)dst)[i] = PIXEL_AiRGB( 0xff, src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_RGB555: + for (i = 0; i < len; i++) + ((u16*)dst)[i] = PIXEL_RGB555( src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_BGR555: + for (i = 0; i < len; i++) + ((u16*)dst)[i] = PIXEL_BGR555( src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + case DSPF_RGB444: + for (i = 0; i < len; i++) + ((u16*)dst)[i] = PIXEL_RGB444( src[i*3+0], src[i*3+1], src[i*3+2] ); + break; + + default: + D_ONCE( "unimplemented destination format (0x%08x)", format ); + break; + } +} + +static inline void +copy_line_nv16( u16 *yy, u16 *cbcr, const u8 *src_ycbcr, int width ) +{ + int x; + + D_ASSUME( !(width & 1) ); + + for (x=0; x> 1); + + src_ycbcr += 6; + } +} + +static inline void +copy_line_y( u16 *yy, const u8 *src_ycbcr, int width ) +{ + int x; + + D_ASSUME( !(width & 1) ); + + for (x=0; xx2 - clip->x1 + 1; + ch = clip->y2 - clip->y1 + 1; + + if (cw < 1 || ch < 1) + return DR_INVAREA; + + D_DEBUG_AT( SH7722_JPEG, "%s( %p, %p|%d [%dx%d] %s )\n", __FUNCTION__, + info, addr, pitch, info->width, info->height, + dfb_pixelformat_name(format) ); + + D_DEBUG_AT( SH7722_JPEG, " -> %d,%d - %4dx%4d [clip %d,%d - %4dx%4d]\n", + DFB_RECTANGLE_VALS( rect ), DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); + + /* No cropping or clipping yet :( */ + if (clip->x1 != 0 || clip->y1 != 0 || + clip->x2 != rect->w - 1 || clip->y2 != rect->h - 1 || rect->w != width || rect->h != height) + { + D_UNIMPLEMENTED(); + return DR_UNIMPLEMENTED; + } + + info->cinfo.output_components = 3; + + /* Calculate destination base address. */ + addr += DFB_BYTES_PER_LINE( format, rect->x ) + rect->y * pitch; + + /* Not all formats yet :( */ + switch (format) { + case DSPF_RGB332: + case DSPF_ARGB1555: + case DSPF_ARGB2554: + case DSPF_ARGB4444: + case DSPF_RGB16: + case DSPF_RGB24: + case DSPF_RGB32: + case DSPF_ARGB: + case DSPF_AiRGB: + case DSPF_RGB555: + case DSPF_BGR555: + case DSPF_RGB444: + info->cinfo.out_color_space = JCS_RGB; + break; + + case DSPF_NV12: + if (rect->x & 1) + return DFB_INVARG; + + if (rect->y & 1) + return DFB_INVARG; + + addr_uv += rect->x + rect->y / 2 * pitch; + + info->cinfo.out_color_space = JCS_YCbCr; + break; + + case DSPF_NV16: + if (rect->x & 1) + return DFB_INVARG; + + addr_uv += rect->x + rect->y * pitch; + + info->cinfo.out_color_space = JCS_YCbCr; + break; + + default: + D_UNIMPLEMENTED(); + return DR_UNIMPLEMENTED; + } + + D_DEBUG_AT( SH7722_JPEG, " -> decoding...\n" ); + + jpeg_start_decompress( &info->cinfo ); + + row_stride = ((info->cinfo.output_width + 1) & ~1) * 3; + + buffer = (*info->cinfo.mem->alloc_sarray)((j_common_ptr) &info->cinfo, JPOOL_IMAGE, row_stride, 1); + + while (info->cinfo.output_scanline < info->cinfo.output_height) { + jpeg_read_scanlines( &info->cinfo, buffer, 1 ); + + switch (format) { + case DSPF_NV12: + if (info->cinfo.output_scanline & 1) { + copy_line_nv16( addr, addr_uv, *buffer, (rect->w + 1) & ~1 ); + addr_uv += pitch; + } + else + copy_line_y( addr, *buffer, (rect->w + 1) & ~1 ); + break; + + case DSPF_NV16: + copy_line_nv16( addr, addr_uv, *buffer, (rect->w + 1) & ~1 ); + addr_uv += pitch; + break; + + default: + write_rgb_span( *buffer, addr, rect->w, format ); + break; + } + + addr += pitch; + } + + jpeg_finish_decompress( &info->cinfo ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DirectResult +Initialize_GFX( SH7722_JPEG_data *data ) +{ + D_DEBUG_AT( SH7722_JPEG, "%s( %p )\n", __FUNCTION__, data ); + + /* Open the drawing engine device. */ + data->gfx_fd = direct_try_open( "/dev/sh772x_gfx", "/dev/misc/sh772x_gfx", O_RDWR, true ); + if (data->gfx_fd < 0) + return DR_INIT; + + /* Map its shared data. */ + data->gfx_shared = mmap( NULL, direct_page_align( sizeof(SH772xGfxSharedArea) ), + PROT_READ | PROT_WRITE, + MAP_SHARED, data->gfx_fd, 0 ); + if (data->gfx_shared == MAP_FAILED) { + D_PERROR( "SH7722/GFX: Could not map shared area!\n" ); + close( data->gfx_fd ); + return DR_INIT; + } + + D_DEBUG_AT( SH7722_JPEG, " -> magic 0x%08x\n", data->gfx_shared->magic ); + D_DEBUG_AT( SH7722_JPEG, " -> buffer 0x%08lx\n", data->gfx_shared->buffer_phys ); + D_DEBUG_AT( SH7722_JPEG, " -> jpeg 0x%08lx\n", data->gfx_shared->jpeg_phys ); + + /* Check the magic value. */ + if (data->gfx_shared->magic != SH7722GFX_SHARED_MAGIC) { + D_ERROR( "SH7722/GFX: Magic value 0x%08x doesn't match 0x%08x!\n", + data->gfx_shared->magic, SH7722GFX_SHARED_MAGIC ); + munmap( (void*) data->gfx_shared, direct_page_align( sizeof(SH772xGfxSharedArea) ) ); + close( data->gfx_fd ); + return DR_INIT; + } + + return DR_OK; +} + +static DirectResult +Shutdown_GFX( SH7722_JPEG_data *data ) +{ + munmap( (void*) data->gfx_shared, direct_page_align( sizeof(SH772xGfxSharedArea) ) ); + + close( data->gfx_fd ); + + return DR_OK; +} + +/**********************************************************************************************************************/ + +static DirectResult +Initialize_Mem( SH7722_JPEG_data *data, + unsigned long phys ) +{ + int fd; + + D_DEBUG_AT( SH7722_JPEG, "%s( %p, 0x%08lx )\n", __FUNCTION__, data, phys ); + + fd = open( "/dev/mem", O_RDWR | O_SYNC ); + if (fd < 0) { + D_PERROR( "SH7722/JPEG: Could not open /dev/mem!\n" ); + return DR_INIT; + } + + data->jpeg_virt = mmap( NULL, direct_page_align( SH7722GFX_JPEG_SIZE ), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, phys ); + if (data->jpeg_virt == MAP_FAILED) { + D_PERROR( "SH7722/JPEG: Could not map /dev/mem at 0x%08lx (length %lu)!\n", + phys, direct_page_align( SH7722GFX_JPEG_SIZE ) ); + close( fd ); + return DR_INIT; + } + + data->jpeg_phys = phys; + data->jpeg_lb1 = data->jpeg_phys + SH7722GFX_JPEG_RELOAD_SIZE * 2; + data->jpeg_lb2 = data->jpeg_lb1 + SH7722GFX_JPEG_LINEBUFFER_SIZE; + + close( fd ); + + return DR_OK; +} + +static DirectResult +Shutdown_Mem( SH7722_JPEG_data *data ) +{ + munmap( (void*) data->jpeg_virt, direct_page_align( SH7722GFX_JPEG_SIZE ) ); + + return DR_OK; +} + +/**********************************************************************************************************************/ + +#define JPEG_PROG_BUF_SIZE 0x10000 + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + JOCTET *data; /* start of buffer */ + + DirectStream *stream; + + int peekonly; + int peekoffset; +} stream_source_mgr; + +typedef stream_source_mgr * stream_src_ptr; + +static void +stream_init_source (j_decompress_ptr cinfo) +{ + stream_src_ptr src = (stream_src_ptr) cinfo->src; + + direct_stream_seek( src->stream, 0 ); /* ignore return value */ +} + +static boolean +stream_fill_input_buffer (j_decompress_ptr cinfo) +{ + DFBResult ret; + unsigned int nbytes = 0; + stream_src_ptr src = (stream_src_ptr) cinfo->src; + + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 50000; + + direct_stream_wait( src->stream, JPEG_PROG_BUF_SIZE, &tv ); + + if (src->peekonly) { + ret = direct_stream_peek( src->stream, JPEG_PROG_BUF_SIZE, src->peekoffset, src->data, &nbytes ); + if (ret && ret != DFB_EOF) + D_DERROR( ret, "SH7722/JPEG: direct_stream_peek() failed!\n" ); + + src->peekoffset += MAX( nbytes, 0 ); + } + else { + ret = direct_stream_read( src->stream, JPEG_PROG_BUF_SIZE, src->data, &nbytes ); + if (ret && ret != DFB_EOF) + D_DERROR( ret, "SH7722/JPEG: direct_stream_read() failed!\n" ); + } + + if (ret || nbytes <= 0) { + /* Insert a fake EOI marker */ + src->data[0] = (JOCTET) 0xFF; + src->data[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->data; + src->pub.bytes_in_buffer = nbytes; + + return TRUE; +} + +static void +stream_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + stream_src_ptr src = (stream_src_ptr) cinfo->src; + + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void)stream_fill_input_buffer(cinfo); + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +static void +stream_term_source (j_decompress_ptr cinfo) +{ +} + +static void +jpeg_stream_src (j_decompress_ptr cinfo, DirectStream *stream, int peekonly) +{ + stream_src_ptr src; + + cinfo->src = (struct jpeg_source_mgr *) + cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof (stream_source_mgr)); + + src = (stream_src_ptr) cinfo->src; + + src->data = (JOCTET *) + cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT, + JPEG_PROG_BUF_SIZE * sizeof (JOCTET)); + + src->stream = stream; + src->peekonly = peekonly; + src->peekoffset = 0; + + src->pub.init_source = stream_init_source; + src->pub.fill_input_buffer = stream_fill_input_buffer; + src->pub.skip_input_data = stream_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = stream_term_source; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +static void +jpeglib_panic(j_common_ptr cinfo) +{ + struct my_error_mgr *myerr = (struct my_error_mgr*) cinfo->err; + longjmp(myerr->setjmp_buffer, 1); +} + +/**********************************************************************************************************************/ + +static SH7722_JPEG_data data; + +DirectResult +SH7722_JPEG_Initialize( void ) +{ + DirectResult ret; + + if (data.ref_count) { + data.ref_count++; + return DR_OK; + } + + ret = Initialize_GFX( &data ); + if (ret) + return ret; + + ret = Initialize_Mem( &data, data.gfx_shared->jpeg_phys ); + if (ret) { + Shutdown_GFX( &data ); + return ret; + } + + data.ref_count = 1; + + return DR_OK; +} + +DirectResult +SH7722_JPEG_Shutdown( void ) +{ + if (!data.ref_count) + return DR_DEAD; + + if (--data.ref_count) + return DR_OK; + + Shutdown_Mem( &data ); + + Shutdown_GFX( &data ); + + return DR_OK; +} + +DirectResult +SH7722_JPEG_Open( DirectStream *stream, + SH7722_JPEG_context *context ) +{ + struct my_error_mgr jerr; + + if (!data.ref_count) + return DR_DEAD; + + context->cinfo.err = jpeg_std_error( &jerr.pub ); + jerr.pub.error_exit = jpeglib_panic; + + if (setjmp( jerr.setjmp_buffer )) { + D_ERROR( "SH7722/JPEG: Error while reading headers!\n" ); + + jpeg_destroy_decompress( &context->cinfo ); + return DFB_FAILURE; + } + + jpeg_create_decompress( &context->cinfo ); + jpeg_stream_src( &context->cinfo, stream, 1 ); + jpeg_read_header( &context->cinfo, TRUE ); + jpeg_calc_output_dimensions( &context->cinfo ); + + context->stream = stream; + context->width = context->cinfo.output_width; + context->height = context->cinfo.output_height; + + context->mode420 = context->cinfo.comp_info[1].h_samp_factor == context->cinfo.comp_info[0].h_samp_factor / 2 && + context->cinfo.comp_info[1].v_samp_factor == context->cinfo.comp_info[0].v_samp_factor / 2 && + context->cinfo.comp_info[2].h_samp_factor == context->cinfo.comp_info[0].h_samp_factor / 2 && + context->cinfo.comp_info[2].v_samp_factor == context->cinfo.comp_info[0].v_samp_factor / 2; + + context->mode444 = context->cinfo.comp_info[1].h_samp_factor == context->cinfo.comp_info[0].h_samp_factor && + context->cinfo.comp_info[1].v_samp_factor == context->cinfo.comp_info[0].v_samp_factor && + context->cinfo.comp_info[2].h_samp_factor == context->cinfo.comp_info[0].h_samp_factor && + context->cinfo.comp_info[2].v_samp_factor == context->cinfo.comp_info[0].v_samp_factor; + + return DFB_OK; +} + +DirectResult +SH7722_JPEG_Decode( SH7722_JPEG_context *context, + const DFBRectangle *rect, + const DFBRegion *clip, + DFBSurfacePixelFormat format, + unsigned long phys, + void *addr, + int pitch, + unsigned int width, + unsigned int height ) +{ + DFBResult ret = DFB_UNSUPPORTED; + DFBRectangle _rect; + DFBRegion _clip; + struct my_error_mgr jerr; + bool sw_only = false; + + if (!data.ref_count) + return DR_DEAD; + + context->cinfo.err = jpeg_std_error( &jerr.pub ); + jerr.pub.error_exit = jpeglib_panic; + + if (setjmp( jerr.setjmp_buffer )) { + D_ERROR( "SH7722/JPEG: Error while decoding image!\n" ); + return DFB_FAILURE; + } + + switch (format) { + case DSPF_NV12: + case DSPF_NV16: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_RGB24: + break; + + case DSPF_RGB332: + case DSPF_ARGB1555: + case DSPF_ARGB2554: + case DSPF_ARGB4444: + case DSPF_ARGB: + case DSPF_AiRGB: + case DSPF_RGB555: + case DSPF_BGR555: + case DSPF_RGB444: + sw_only = true; + break; + + default: + return DR_UNSUPPORTED; + } + + if (!rect) { + _rect.x = 0; + _rect.y = 0; + _rect.w = width; + _rect.h = height; + + rect = &_rect; + } + + if (!clip) { + _clip.x1 = _rect.x; + _clip.y1 = _rect.y; + _clip.x2 = _rect.x + _rect.w - 1; + _clip.y2 = _rect.y + _rect.h - 1; + + clip = &_clip; + } + + if (!context->mode444 && !sw_only) + ret = DecodeHW( &data, context, rect, clip, format, phys, pitch, width, height ); + + if (ret) { + if (addr) { + ret = DecodeSW( context, rect, clip, format, addr, pitch, width, height ); + } + else { + int fd, len = direct_page_align( DFB_PLANE_MULTIPLY( format, height ) * pitch ); + + fd = open( "/dev/mem", O_RDWR | O_SYNC ); + if (fd < 0) { + D_PERROR( "SH7722/JPEG: Could not open /dev/mem!\n" ); + return DR_INIT; + } + + addr = mmap( NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, phys ); + if (addr == MAP_FAILED) { + D_PERROR( "SH7722/JPEG: Could not map /dev/mem at 0x%08lx (length %d)!\n", phys, len ); + close( fd ); + return DR_INIT; + } + + ret = DecodeSW( context, rect, clip, format, addr, pitch, width, height ); + + munmap( addr, len ); + } + } + + return ret; +} + + +DirectResult +SH7722_JPEG_Close( SH7722_JPEG_context *context ) +{ + jpeg_destroy_decompress( &context->cinfo ); + + return DFB_OK; +} + +DirectResult +SH7722_JPEG_Encode( const char *filename, + const DFBRectangle *srcrect, + DFBSurfacePixelFormat srcformat, + unsigned long srcphys, + int srcpitch, + unsigned int width, + unsigned int height, + unsigned int tmpphys ) +{ + DFBRectangle _rect; + + if (!data.ref_count) + return DR_DEAD; + + switch (srcformat) { + case DSPF_NV12: + case DSPF_NV16: + case DSPF_RGB16: + case DSPF_RGB32: + case DSPF_RGB24: + break; + + default: + return DR_UNSUPPORTED; + } + + if (!srcrect) { + _rect.x = 0; + _rect.y = 0; + _rect.w = width; + _rect.h = height; + + srcrect = &_rect; + } + + return EncodeHW( &data, filename, srcrect, srcformat, srcphys, srcpitch, width, height, tmpphys ); +} + -- cgit