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/src/core/surface_buffer.c | 1206 +++++++++++++++++++++++++++++ 1 file changed, 1206 insertions(+) create mode 100755 Source/DirectFB/src/core/surface_buffer.c (limited to 'Source/DirectFB/src/core/surface_buffer.c') diff --git a/Source/DirectFB/src/core/surface_buffer.c b/Source/DirectFB/src/core/surface_buffer.c new file mode 100755 index 0000000..da477df --- /dev/null +++ b/Source/DirectFB/src/core/surface_buffer.c @@ -0,0 +1,1206 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include + +#include +#include +#include +#include + +#ifdef USE_ZLIB +#include +#endif + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +static const u8 lookup3to8[] = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; +static const u8 lookup2to8[] = { 0x00, 0x55, 0xaa, 0xff }; + + +D_DEBUG_DOMAIN( Core_SurfBuffer, "Core/SurfBuffer", "DirectFB Core Surface Buffer" ); + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_buffer_new( CoreSurface *surface, + CoreSurfaceBufferFlags flags, + CoreSurfaceBuffer **ret_buffer ) +{ + CoreSurfaceBuffer *buffer; + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_FLAGS_ASSERT( flags, CSBF_ALL ); + D_ASSERT( ret_buffer != NULL ); + +#if DIRECT_BUILD_DEBUG + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_new( %s )\n", dfb_pixelformat_name( surface->config.format ) ); + + if (flags & CSBF_STICKED) + D_DEBUG_AT( Core_SurfBuffer, " -> STICKED\n" ); +#endif + + buffer = SHCALLOC( surface->shmpool, 1, sizeof(CoreSurfaceBuffer) ); + if (!buffer) + return D_OOSHM(); + + direct_serial_init( &buffer->serial ); + direct_serial_increase( &buffer->serial ); + + buffer->surface = surface; + buffer->flags = flags; + buffer->format = surface->config.format; + + if (surface->config.caps & DSCAPS_VIDEOONLY) + buffer->policy = CSP_VIDEOONLY; + else if (surface->config.caps & DSCAPS_SYSTEMONLY) + buffer->policy = CSP_SYSTEMONLY; + else + buffer->policy = CSP_VIDEOLOW; + + fusion_vector_init( &buffer->allocs, 2, surface->shmpool ); + + D_MAGIC_SET( buffer, CoreSurfaceBuffer ); + + *ret_buffer = buffer; + + return DFB_OK; +} + +DFBResult +dfb_surface_buffer_destroy( CoreSurfaceBuffer *buffer ) +{ + CoreSurface *surface; + CoreSurfaceAllocation *allocation; + int i; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_destroy( %p [%dx%d] )\n", + buffer, surface->config.size.w, surface->config.size.h ); + + fusion_vector_foreach_reverse (allocation, i, buffer->allocs) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + + fusion_vector_destroy( &buffer->allocs ); + + direct_serial_deinit( &buffer->serial ); + + D_MAGIC_CLEAR( buffer ); + + SHFREE( surface->shmpool, buffer ); + + return DFB_OK; +} + +static CoreSurfaceAllocation * +find_allocation( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags flags, + bool lock ) +{ + int i; + CoreSurfaceAllocation *alloc; + CoreSurfaceAllocation *uptodate = NULL; + CoreSurfaceAllocation *outdated = NULL; + + /* Prefer allocations which are up to date. */ + fusion_vector_foreach (alloc, i, buffer->allocs) { + if (direct_serial_check( &alloc->serial, &buffer->serial )) { + /* Return immediately if up to date allocation has required flags. */ + if (D_FLAGS_ARE_SET( alloc->access[accessor], flags )) + return alloc; + + /* Remember up to date allocation in case none has supported flags. */ + uptodate = alloc; + } + else if (D_FLAGS_ARE_SET( alloc->access[accessor], flags )) { + /* Remember outdated allocation which has supported flags though. */ + outdated = alloc; + } + } + + /* In case of a lock the flags are mandatory and the outdated allocation has to be used... */ + if (lock) + return outdated; + + /* ...otherwise we can still prefer the up to date allocation for Read/Write()! */ + return uptodate ?: outdated; +} + +DFBResult +dfb_surface_buffer_lock( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + CoreSurface *surface; + CoreSurfaceAllocation *allocation = NULL; + bool allocated = false; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_FLAGS_ASSERT( access, CSAF_ALL ); + D_ASSERT( lock != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + D_ASSERT( accessor >= CSAID_CPU ); + D_ASSUME( accessor < _CSAID_NUM ); + if (accessor >= CSAID_ANY) { + D_UNIMPLEMENTED(); + return DFB_UNIMPLEMENTED; + } + + if (accessor < 0 || accessor >= _CSAID_NUM) + return DFB_INVARG; + +#if DIRECT_BUILD_DEBUG + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_lock( %p, 0x%02x, %p ) <- %dx%d %s [%d]\n", buffer, access, lock, + surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(buffer->format), + dfb_surface_buffer_index(buffer) ); + + switch (accessor) { + case CSAID_CPU: + D_DEBUG_AT( Core_SurfBuffer, " -> CPU %s%s\n", + (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); + break; + + case CSAID_GPU: + D_DEBUG_AT( Core_SurfBuffer, " -> GPU %s%s\n", + (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); + break; + + case CSAID_LAYER0: + case CSAID_LAYER1: + case CSAID_LAYER2: + case CSAID_LAYER3: + case CSAID_LAYER4: + case CSAID_LAYER5: + case CSAID_LAYER6: + case CSAID_LAYER7: + D_DEBUG_AT( Core_SurfBuffer, " -> LAYER %d %s%s\n", accessor - CSAID_LAYER0, + (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); + break; + + default: + D_DEBUG_AT( Core_SurfBuffer, " -> other\n" ); + break; + } + + if (access & CSAF_SHARED) + D_DEBUG_AT( Core_SurfBuffer, " -> SHARED\n" ); +#endif + + /* Look for allocation with proper access. */ + allocation = find_allocation( buffer, accessor, access, true ); + if (!allocation) { + /* If no allocation exists, create one. */ + ret = dfb_surface_pools_allocate( buffer, accessor, access, &allocation ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" ); + return ret; + } + + allocated = true; + } + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + /* Synchronize with other allocations. */ + ret = dfb_surface_allocation_update( allocation, access ); + if (ret) { + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + return ret; + } + + /* Lock the allocation. */ + dfb_surface_buffer_lock_init( lock, accessor, access ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n", + allocation->pool->desc.name ); + dfb_surface_buffer_lock_deinit( lock ); + + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + + return ret; + } + +#if 1 + /* + * Manage access interlocks. + * + * SOON FIXME: Clearing flags only when not locked yet. Otherwise nested GPU/CPU locks are a problem. + */ + /* Software read/write access... */ + if (accessor == CSAID_CPU) { + /* If hardware has written or is writing... */ + if (allocation->accessed[CSAID_GPU] & CSAF_WRITE) { + /* ...wait for the operation to finish. */ + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + /* Software read access after hardware write requires flush of the (bus) read cache. */ + dfb_gfxcard_flush_read_cache(); + + if (!buffer->locked) { + /* ...clear hardware write access. */ + allocation->accessed[CSAID_GPU] &= ~CSAF_WRITE; + + /* ...clear hardware read access (to avoid syncing twice). */ + allocation->accessed[CSAID_GPU] &= ~CSAF_READ; + } + } + + /* Software write access... */ + if (access & CSAF_WRITE) { + /* ...if hardware has (to) read... */ + if (allocation->accessed[CSAID_GPU] & CSAF_READ) { + /* ...wait for the operation to finish. */ + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + /* ...clear hardware read access. */ + if (!buffer->locked) + allocation->accessed[CSAID_GPU] &= ~CSAF_READ; + } + } + } + + /* Hardware read access... */ + if (accessor == CSAID_GPU && access & CSAF_READ) { + /* ...if software has written before... */ + if (allocation->accessed[CSAID_CPU] & CSAF_WRITE) { + /* ...flush texture cache. */ + dfb_gfxcard_flush_texture_cache(); + + /* ...clear software write access. */ + if (!buffer->locked) + allocation->accessed[CSAID_CPU] &= ~CSAF_WRITE; + } + } + + if (! D_FLAGS_ARE_SET( allocation->accessed[accessor], access )) { + /* FIXME: surface_enter */ + } +#endif + + /* Collect... */ + allocation->accessed[accessor] |= access; + +#if 1 + /* FIXME: don't use weak counter */ + buffer->locked++; + + D_DEBUG_AT( Core_SurfBuffer, " -> locked %dx now\n", buffer->locked ); +#endif + + return DFB_OK; +} + +DFBResult +dfb_surface_buffer_unlock( CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + CoreSurfacePool *pool; + CoreSurfaceBuffer *buffer; + CoreSurfaceAllocation *allocation; + + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_unlock( %p )\n", lock ); + + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + D_MAGIC_ASSERT( lock->buffer, CoreSurfaceBuffer ); + D_MAGIC_ASSERT( lock->buffer->surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &lock->buffer->surface->lock ); + + allocation = lock->allocation; + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + buffer = lock->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + pool = allocation->pool; + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + /* + * FIXME: This should fail with a nested GPU Lock during a CPU Lock and/or vice versa? + */ +// D_ASSUME( D_FLAGS_ARE_SET( allocation->accessed, lock->access ) ); + + ret = dfb_surface_pool_unlock( pool, lock->allocation, lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", pool->desc.name ); + return ret; + } + +#if 1 + buffer->locked--; +#endif + + dfb_surface_buffer_lock_reset( lock ); + + dfb_surface_buffer_lock_deinit( lock ); + + return DFB_OK; +} + +DFBResult +dfb_surface_buffer_read( CoreSurfaceBuffer *buffer, + void *destination, + int pitch, + const DFBRectangle *prect ) +{ + DFBResult ret; + int y; + int bytes; + DFBRectangle rect; + CoreSurface *surface; + CoreSurfaceAllocation *allocation = NULL; + bool allocated = false; + DFBSurfacePixelFormat format; + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p [%d] )\n", __FUNCTION__, buffer, destination, pitch ); + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_ASSERT( destination != NULL ); + D_ASSERT( pitch > 0 ); + DFB_RECTANGLE_ASSERT_IF( prect ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + /* Determine area. */ + rect.x = 0; + rect.y = 0; + rect.w = surface->config.size.w; + rect.h = surface->config.size.h; + + if (prect && (!dfb_rectangle_intersect( &rect, prect ) || !DFB_RECTANGLE_EQUAL( rect, *prect ))) + return DFB_INVAREA; + + /* Calculate bytes per read line. */ + format = surface->config.format; + bytes = DFB_BYTES_PER_LINE( format, rect.w ); + + D_DEBUG_AT( Core_SurfBuffer, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect), + dfb_pixelformat_name( format ) ); + + /* If no allocations exists, simply clear the destination. */ + if (fusion_vector_is_empty( &buffer->allocs )) { + for (y=0; ywritten && direct_serial_check( &buffer->written->serial, &buffer->serial )) + allocation = buffer->written; + else { + /* ...otherwise look for allocation with CPU access. */ + allocation = find_allocation( buffer, CSAID_CPU, CSAF_READ, false ); + if (!allocation) { + /* If no allocation exists, create one. */ + ret = dfb_surface_pools_allocate( buffer, CSAID_CPU, CSAF_READ, &allocation ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" ); + return ret; + } + + allocated = true; + } + } + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + /* Synchronize with other allocations. */ + ret = dfb_surface_allocation_update( allocation, CSAF_READ ); + if (ret) { + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + return ret; + } + + /* Try reading from allocation directly... */ + ret = dfb_surface_pool_read( allocation->pool, allocation, destination, pitch, &rect ); + if (ret) { + /* ...otherwise use fallback method via locking if possible. */ + if (allocation->access[CSAID_CPU] & CSAF_READ) { + CoreSurfaceBufferLock lock; + + /* Lock the allocation. */ + dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_READ ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n", + allocation->pool->desc.name ); + dfb_surface_buffer_lock_deinit( &lock ); + return ret; + } + + /* Move to start of read. */ + lock.addr += DFB_BYTES_PER_LINE( format, rect.x ) + rect.y * lock.pitch; + + /* Copy the data. */ + for (y=0; ypool, allocation, &lock ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name ); + + dfb_surface_buffer_lock_deinit( &lock ); + } + } + + return ret; +} + +DFBResult +dfb_surface_buffer_write( CoreSurfaceBuffer *buffer, + const void *source, + int pitch, + const DFBRectangle *prect ) +{ + DFBResult ret; + DFBRectangle rect; + CoreSurface *surface; + CoreSurfaceAllocation *allocation = NULL; + bool allocated = false; + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p [%d] )\n", __FUNCTION__, buffer, source, pitch ); + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_ASSERT( pitch > 0 || source == NULL ); + DFB_RECTANGLE_ASSERT_IF( prect ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + /* Determine area. */ + rect.x = 0; + rect.y = 0; + rect.w = surface->config.size.w; + rect.h = surface->config.size.h; + + if (prect && (!dfb_rectangle_intersect( &rect, prect ) || !DFB_RECTANGLE_EQUAL( rect, *prect ))) + return DFB_INVAREA; + + D_DEBUG_AT( Core_SurfBuffer, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect), + dfb_pixelformat_name( surface->config.format ) ); + + /* Use last read allocation if it's up to date... */ + if (buffer->read && direct_serial_check( &buffer->read->serial, &buffer->serial )) + allocation = buffer->read; + else { + /* ...otherwise look for allocation with CPU access. */ + allocation = find_allocation( buffer, CSAID_CPU, CSAF_WRITE, false ); + if (!allocation) { + /* If no allocation exists, create one. */ + ret = dfb_surface_pools_allocate( buffer, CSAID_CPU, CSAF_WRITE, &allocation ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" ); + return ret; + } + + allocated = true; + } + } + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + /* Synchronize with other allocations. */ + ret = dfb_surface_allocation_update( allocation, CSAF_WRITE ); + if (ret) { + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + return ret; + } + + /* Try writing to allocation directly... */ + ret = source ? dfb_surface_pool_write( allocation->pool, allocation, source, pitch, &rect ) : DFB_UNSUPPORTED; + if (ret) { + /* ...otherwise use fallback method via locking if possible. */ + if (allocation->access[CSAID_CPU] & CSAF_WRITE) { + int y; + int bytes; + DFBSurfacePixelFormat format; + CoreSurfaceBufferLock lock; + + /* Calculate bytes per written line. */ + format = surface->config.format; + bytes = DFB_BYTES_PER_LINE( format, rect.w ); + + /* Lock the allocation. */ + dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_WRITE ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n", + allocation->pool->desc.name ); + dfb_surface_buffer_lock_deinit( &lock ); + return ret; + } + + /* Move to start of write. */ + lock.addr += DFB_BYTES_PER_LINE( format, rect.x ) + rect.y * lock.pitch; + + /* Copy the data. */ + for (y=0; ypool, allocation, &lock ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name ); + + dfb_surface_buffer_lock_deinit( &lock ); + } + } + + return ret; +} + +DFBResult +dfb_surface_buffer_dump( CoreSurfaceBuffer *buffer, + const char *directory, + const char *prefix ) +{ + DFBResult ret; + int num = -1; + int fd_p = -1; + int fd_g = -1; + int i, n; + int len = (directory ? strlen(directory) : 0) + (prefix ? strlen(prefix) : 0) + 40; + char filename[len]; + char head[30]; + bool rgb = false; + bool alpha = false; +#ifdef USE_ZLIB + gzFile gz_p = NULL, gz_g = NULL; + static const char *gz_ext = ".gz"; +#else + static const char *gz_ext = ""; +#endif + CoreSurface *surface; + CorePalette *palette = NULL; + CoreSurfaceBufferLock lock; + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p, %p )\n", __FUNCTION__, buffer, directory, prefix ); + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_ASSERT( directory != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + /* Check pixel format. */ + switch (buffer->format) { + case DSPF_LUT8: + palette = surface->palette; + + if (!palette) { + D_BUG( "no palette" ); + return DFB_BUG; + } + + if (dfb_palette_ref( palette )) + return DFB_FUSION; + + rgb = true; + + /* fall through */ + + case DSPF_A8: + alpha = true; + break; + + case DSPF_ARGB: + case DSPF_ARGB1555: + case DSPF_ARGB2554: + case DSPF_ARGB4444: + case DSPF_AiRGB: + alpha = true; + + /* fall through */ + + case DSPF_RGB332: + case DSPF_RGB16: + case DSPF_RGB24: + case DSPF_RGB32: + case DSPF_YUY2: + case DSPF_UYVY: + case DSPF_NV16: + case DSPF_RGB444: + case DSPF_RGB555: + case DSPF_BGR555: + rgb = true; + break; + + + default: + D_ERROR( "DirectFB/core/surfaces: surface dump for format " + "'%s' is not implemented!\n", + dfb_pixelformat_name( buffer->format ) ); + return DFB_UNSUPPORTED; + } + + /* Lock the surface buffer, get the data pointer and pitch. */ + ret = dfb_surface_buffer_lock( buffer, CSAID_CPU, CSAF_READ, &lock ); + if (ret) { + if (palette) + dfb_palette_unref( palette ); + return ret; + } + + if (prefix) { + /* Find the lowest unused index. */ + while (++num < 10000) { + snprintf( filename, len, "%s/%s_%04d.ppm%s", + directory, prefix, num, gz_ext ); + + if (access( filename, F_OK ) != 0) { + snprintf( filename, len, "%s/%s_%04d.pgm%s", + directory, prefix, num, gz_ext ); + + if (access( filename, F_OK ) != 0) + break; + } + } + + if (num == 10000) { + D_ERROR( "DirectFB/core/surfaces: " + "couldn't find an unused index for surface dump!\n" ); + dfb_surface_buffer_unlock( &lock ); + if (palette) + dfb_palette_unref( palette ); + return DFB_FAILURE; + } + } + + /* Create a file with the found index. */ + if (rgb) { + if (prefix) + snprintf( filename, len, "%s/%s_%04d.ppm%s", directory, prefix, num, gz_ext ); + else + snprintf( filename, len, "%s.ppm%s", directory, gz_ext ); + + fd_p = open( filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); + if (fd_p < 0) { + D_PERROR("DirectFB/core/surfaces: " + "could not open %s!\n", filename); + dfb_surface_buffer_unlock( &lock ); + if (palette) + dfb_palette_unref( palette ); + return DFB_IO; + } + } + + /* Create a graymap for the alpha channel using the found index. */ + if (alpha) { + if (prefix) + snprintf( filename, len, "%s/%s_%04d.pgm%s", directory, prefix, num, gz_ext ); + else + snprintf( filename, len, "%s.pgm%s", directory, gz_ext ); + + fd_g = open( filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); + if (fd_g < 0) { + D_PERROR("DirectFB/core/surfaces: " + "could not open %s!\n", filename); + + dfb_surface_buffer_unlock( &lock ); + if (palette) + dfb_palette_unref( palette ); + + if (rgb) { + close( fd_p ); + snprintf( filename, len, "%s/%s_%04d.ppm%s", + directory, prefix, num, gz_ext ); + unlink( filename ); + } + + return DFB_IO; + } + } + +#ifdef USE_ZLIB + if (rgb) + gz_p = gzdopen( fd_p, "wb" ); + + if (alpha) + gz_g = gzdopen( fd_g, "wb" ); +#endif + + if (rgb) { + /* Write the pixmap header. */ + snprintf( head, 30, + "P6\n%d %d\n255\n", surface->config.size.w, surface->config.size.h ); +#ifdef USE_ZLIB + gzwrite( gz_p, head, strlen(head) ); +#else + write( fd_p, head, strlen(head) ); +#endif + } + + /* Write the graymap header. */ + if (alpha) { + snprintf( head, 30, + "P5\n%d %d\n255\n", surface->config.size.w, surface->config.size.h ); +#ifdef USE_ZLIB + gzwrite( gz_g, head, strlen(head) ); +#else + write( fd_g, head, strlen(head) ); +#endif + } + + /* Write the pixmap (and graymap) data. */ + for (i=0; iconfig.size.h; i++) { + int n3; + + /* Prepare one row. */ + u8 *src8 = dfb_surface_data_offset( surface, lock.addr, lock.pitch, 0, i ); + + /* Write color buffer to pixmap file. */ + if (rgb) { + u8 buf_p[surface->config.size.w * 3]; + + if (buffer->format == DSPF_LUT8) { + for (n=0, n3=0; nconfig.size.w; n++, n3+=3) { + buf_p[n3+0] = palette->entries[src8[n]].r; + buf_p[n3+1] = palette->entries[src8[n]].g; + buf_p[n3+2] = palette->entries[src8[n]].b; + } + } + else + dfb_convert_to_rgb24( buffer->format, src8, lock.pitch, surface->config.size.h, + buf_p, surface->config.size.w * 3, surface->config.size.w, 1 ); +#ifdef USE_ZLIB + gzwrite( gz_p, buf_p, surface->config.size.w * 3 ); +#else + write( fd_p, buf_p, surface->config.size.w * 3 ); +#endif + } + + /* Write alpha buffer to graymap file. */ + if (alpha) { + u8 buf_g[surface->config.size.w]; + + if (buffer->format == DSPF_LUT8) { + for (n=0; nconfig.size.w; n++) + buf_g[n] = palette->entries[src8[n]].a; + } + else + dfb_convert_to_a8( buffer->format, src8, lock.pitch, surface->config.size.h, + buf_g, surface->config.size.w, surface->config.size.w, 1 ); +#ifdef USE_ZLIB + gzwrite( gz_g, buf_g, surface->config.size.w ); +#else + write( fd_g, buf_g, surface->config.size.w ); +#endif + } + } + + /* Unlock the surface buffer. */ + dfb_surface_buffer_unlock( &lock ); + + /* Release the palette. */ + if (palette) + dfb_palette_unref( palette ); + +#ifdef USE_ZLIB + if (rgb) + gzclose( gz_p ); + + if (alpha) + gzclose( gz_g ); +#endif + + /* Close pixmap file. */ + if (rgb) + close( fd_p ); + + /* Close graymap file. */ + if (alpha) + close( fd_g ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static void +transfer_buffer( CoreSurfaceBuffer *buffer, + const void *src, + void *dst, + int srcpitch, + int dstpitch ) +{ + int i; + CoreSurface *surface; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p [%d] -> %p [%d] ) * %d\n", + __FUNCTION__, buffer, src, srcpitch, dst, dstpitch, surface->config.size.h ); + + D_ASSERT( src != NULL ); + D_ASSERT( dst != NULL ); + D_ASSERT( srcpitch > 0 ); + D_ASSERT( dstpitch > 0 ); + + D_ASSERT( srcpitch >= DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + D_ASSERT( dstpitch >= DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + + for (i=0; iconfig.size.h; i++) { + direct_memcpy( dst, src, DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + + src += srcpitch; + dst += dstpitch; + } + + switch (buffer->format) { + case DSPF_YV12: + case DSPF_I420: + for (i=0; iconfig.size.h; i++) { + direct_memcpy( dst, src, + DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w / 2 ) ); + src += srcpitch / 2; + dst += dstpitch / 2; + } + break; + + case DSPF_NV12: + case DSPF_NV21: + for (i=0; iconfig.size.h/2; i++) { + direct_memcpy( dst, src, + DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + src += srcpitch; + dst += dstpitch; + } + break; + + case DSPF_NV16: + for (i=0; iconfig.size.h; i++) { + direct_memcpy( dst, src, + DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + src += srcpitch; + dst += dstpitch; + } + break; + + default: + break; + } +} + +static DFBResult +allocation_update_copy( CoreSurfaceAllocation *allocation, + CoreSurfaceAllocation *source ) +{ + DFBResult ret; + CoreSurfaceBufferLock src; + CoreSurfaceBufferLock dst; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_ASSERT( allocation != source ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + + D_ASSERT( source->buffer == allocation->buffer ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the source allocation. */ + dfb_surface_buffer_lock_init( &src, CSAID_CPU, CSAF_READ ); + + ret = dfb_surface_pool_lock( source->pool, source, &src ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock source for transfer!\n" ); + dfb_surface_buffer_lock_deinit( &src ); + return ret; + } + + /* Lock the destination allocation. */ + dfb_surface_buffer_lock_init( &dst, CSAID_CPU, CSAF_WRITE ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &dst ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock destination for transfer!\n" ); + dfb_surface_pool_unlock( source->pool, source, &src ); + return ret; + } + + transfer_buffer( buffer, src.addr, dst.addr, src.pitch, dst.pitch ); + + dfb_surface_pool_unlock( allocation->pool, allocation, &dst ); + dfb_surface_pool_unlock( source->pool, source, &src ); + + dfb_surface_buffer_lock_deinit( &dst ); + dfb_surface_buffer_lock_deinit( &src ); + + return DFB_OK; +} + +static DFBResult +allocation_update_write( CoreSurfaceAllocation *allocation, + CoreSurfaceAllocation *source ) +{ + DFBResult ret; + CoreSurfaceBufferLock src; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_ASSERT( allocation != source ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + + D_ASSERT( source->buffer == allocation->buffer ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the source allocation. */ + dfb_surface_buffer_lock_init( &src, CSAID_CPU, CSAF_READ ); + + ret = dfb_surface_pool_lock( source->pool, source, &src ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock source for transfer!\n" ); + dfb_surface_buffer_lock_deinit( &src ); + return ret; + } + + /* Write to the destination allocation. */ + ret = dfb_surface_pool_write( allocation->pool, allocation, src.addr, src.pitch, NULL ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Could not write from destination allocation!\n" ); + + dfb_surface_pool_unlock( source->pool, source, &src ); + + dfb_surface_buffer_lock_deinit( &src ); + + return ret; +} + +static DFBResult +allocation_update_read( CoreSurfaceAllocation *allocation, + CoreSurfaceAllocation *source ) +{ + DFBResult ret; + CoreSurfaceBufferLock dst; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_ASSERT( allocation != source ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + + D_ASSERT( source->buffer == allocation->buffer ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the destination allocation. */ + dfb_surface_buffer_lock_init( &dst, CSAID_CPU, CSAF_WRITE ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &dst ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock destination for transfer!\n" ); + dfb_surface_buffer_lock_deinit( &dst ); + return ret; + } + + /* Read from the source allocation. */ + ret = dfb_surface_pool_read( source->pool, source, dst.addr, dst.pitch, NULL ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Could not read from source allocation!\n" ); + + dfb_surface_pool_unlock( allocation->pool, allocation, &dst ); + + dfb_surface_buffer_lock_deinit( &dst ); + + return ret; +} + +DFBResult +dfb_surface_allocation_update( CoreSurfaceAllocation *allocation, + CoreSurfaceAccessFlags access ) +{ + DFBResult ret; + int i; + CoreSurfaceAllocation *alloc; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_FLAGS_ASSERT( access, CSAF_ALL ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + if (direct_serial_update( &allocation->serial, &buffer->serial ) && buffer->written) { + CoreSurfaceAllocation *source = buffer->written; + + D_ASSUME( allocation != source ); + + D_DEBUG_AT( Core_SurfBuffer, " -> updating allocation...\n" ); + + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + D_ASSERT( source->buffer == allocation->buffer ); + + ret = dfb_surface_pool_bridges_transfer( buffer, source, allocation, NULL, 0 ); + if (ret) { + if ((source->access[CSAID_CPU] & CSAF_READ) && (allocation->access[CSAID_CPU] & CSAF_WRITE)) + ret = allocation_update_copy( allocation, source ); + else if (source->access[CSAID_CPU] & CSAF_READ) + ret = allocation_update_write( allocation, source ); + else if (allocation->access[CSAID_CPU] & CSAF_WRITE) + ret = allocation_update_read( allocation, source ); + else { + D_UNIMPLEMENTED(); + ret = DFB_UNSUPPORTED; + } + } + + if (ret) { + D_DERROR( ret, "Core/SurfaceBuffer: Updating allocation failed!\n" ); + return ret; + } + } + + if (access & CSAF_WRITE) { + D_DEBUG_AT( Core_SurfBuffer, " -> increasing serial...\n" ); + + direct_serial_increase( &buffer->serial ); + + direct_serial_copy( &allocation->serial, &buffer->serial ); + + buffer->written = allocation; + buffer->read = NULL; + + /* Zap volatile allocations (freed when no longer up to date). */ + fusion_vector_foreach (alloc, i, buffer->allocs) { + D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); + + if (alloc != allocation && (alloc->flags & CSALF_VOLATILE)) { + dfb_surface_pool_deallocate( alloc->pool, alloc ); + i--; + } + } + } + else + buffer->read = allocation; + + /* Zap all other allocations? */ + if (dfb_config->thrifty_surface_buffers) { + buffer->written = buffer->read = allocation; + + fusion_vector_foreach (alloc, i, buffer->allocs) { + D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); + + /* Don't zap preallocated which would not really free up memory, but just loose the handle. */ + if (alloc != allocation && !(alloc->flags & (CSALF_PREALLOCATED | CSALF_MUCKOUT))) { + dfb_surface_pool_deallocate( alloc->pool, alloc ); + i--; + } + } + } + + return DFB_OK; +} + -- cgit