void dfb_gfx_copy_to( CoreSurface *source, CoreSurface *destination, const DFBRectangle *rect, int x, int y, bool from_back ) { DFBRectangle sourcerect = { 0, 0, source->config.size.w, source->config.size.h }; pthread_mutex_lock( ©_lock ); if (!copy_state_inited) { dfb_state_init( ©_state, NULL ); copy_state_inited = true; } copy_state.modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION; copy_state.clip.x2 = destination->config.size.w - 1; copy_state.clip.y2 = destination->config.size.h - 1; copy_state.source = source; copy_state.destination = destination; copy_state.from = from_back ? CSBR_BACK : CSBR_FRONT; copy_state.to = CSBR_BACK; if (rect) { if (dfb_rectangle_intersect( &sourcerect, rect )) dfb_gfxcard_blit( &sourcerect, x + sourcerect.x - rect->x, y + sourcerect.y - rect->y, ©_state ); } else dfb_gfxcard_blit( &sourcerect, x, y, ©_state ); /* Signal end of sequence. */ dfb_state_stop_drawing( ©_state ); pthread_mutex_unlock( ©_lock ); }
static DFBResult IDirectFBSurface_Layer_GetSubSurface( IDirectFBSurface *thiz, const DFBRectangle *rect, IDirectFBSurface **surface ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA(IDirectFBSurface_Layer) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); /* Check arguments */ if (!data->base.surface) return DFB_DESTROYED; if (!surface) return DFB_INVARG; /* Allocate interface */ DIRECT_ALLOCATE_INTERFACE( *surface, IDirectFBSurface ); if (rect || data->base.limit_set) { DFBRectangle wanted, granted; /* Compute wanted rectangle */ if (rect) { wanted = *rect; wanted.x += data->base.area.wanted.x; wanted.y += data->base.area.wanted.y; if (wanted.w <= 0 || wanted.h <= 0) { wanted.w = 0; wanted.h = 0; } } else { wanted = data->base.area.wanted; } /* Compute granted rectangle */ granted = wanted; dfb_rectangle_intersect( &granted, &data->base.area.granted ); /* Construct */ ret = IDirectFBSurface_Layer_Construct( *surface, thiz, &wanted, &granted, data->region, data->base.caps | DSCAPS_SUBSURFACE, data->base.core ); } else { /* Construct */ ret = IDirectFBSurface_Layer_Construct( *surface, thiz, NULL, NULL, data->region, data->base.caps | DSCAPS_SUBSURFACE, data->base.core ); } return ret; }
void dfb_gfx_stretch_stereo( CoreSurface *source, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceStereoEye destination_eye, const DFBRectangle *srect, const DFBRectangle *drect, bool from_back ) { DFBRectangle sourcerect = { 0, 0, source->config.size.w, source->config.size.h }; DFBRectangle destrect = { 0, 0, destination->config.size.w, destination->config.size.h }; D_ASSERT( !dfb_config->task_manager ); if (srect) { if (!dfb_rectangle_intersect( &sourcerect, srect )) return; } if (drect) { if (!dfb_rectangle_intersect( &destrect, drect )) return; } StateClient *client = state_client_tls.Get(); D_FLAGS_SET( client->state.modified, SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO ); client->state.clip.x2 = destination->config.size.w - 1; client->state.clip.y2 = destination->config.size.h - 1; client->state.source = source; client->state.destination = destination; client->state.from = from_back ? CSBR_BACK : CSBR_FRONT; client->state.from_eye = source_eye; client->state.to = CSBR_BACK; client->state.to_eye = destination_eye; CoreGraphicsStateClient_StretchBlit( &client->client, &sourcerect, &destrect, 1 ); CoreGraphicsStateClient_Flush( &client->client, 0, CGSCFF_NONE ); /* Signal end of sequence. */ dfb_state_stop_drawing( &client->state ); client->state.destination = NULL; client->state.source = NULL; }
void dfb_gfx_copy_regions_stereo( CoreSurface *source, CoreSurfaceBufferRole from, DFBSurfaceStereoEye source_eye, CoreSurface *destination, CoreSurfaceBufferRole to, DFBSurfaceStereoEye destination_eye, const DFBRegion *regions, unsigned int num, int x, int y ) { unsigned int i, n = 0; DFBRectangle rect = { 0, 0, source->config.size.w, source->config.size.h }; DFBRectangle rects[num]; DFBPoint points[num]; D_ASSERT( !dfb_config->task_manager ); for (i=0; i<num; i++) { DFB_REGION_ASSERT( ®ions[i] ); rects[n] = DFB_RECTANGLE_INIT_FROM_REGION( ®ions[i] ); if (dfb_rectangle_intersect( &rects[n], &rect )) { points[n].x = x + rects[n].x - rect.x; points[n].y = y + rects[n].y - rect.y; n++; } } if (n > 0) { StateClient *client = state_client_tls.Get(); D_FLAGS_SET( client->state.modified, SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO ); client->state.clip.x2 = destination->config.size.w - 1; client->state.clip.y2 = destination->config.size.h - 1; client->state.source = source; client->state.destination = destination; client->state.from = from; client->state.from_eye = source_eye; client->state.to = to; client->state.to_eye = destination_eye; CoreGraphicsStateClient_Blit( &client->client, rects, points, n ); CoreGraphicsStateClient_Flush( &client->client, 0, CGSCFF_NONE ); /* Signal end of sequence. */ dfb_state_stop_drawing( &client->state ); client->state.destination = NULL; client->state.source = NULL; } }
void dfb_gfx_copy_regions( CoreSurface *source, CoreSurfaceBufferRole from, CoreSurface *destination, CoreSurfaceBufferRole to, const DFBRegion *regions, unsigned int num, int x, int y ) { unsigned int i, n = 0; DFBRectangle rect = { 0, 0, source->config.size.w, source->config.size.h }; DFBRectangle rects[num]; DFBPoint points[num]; for (i=0; i<num; i++) { DFB_REGION_ASSERT( ®ions[i] ); rects[n] = DFB_RECTANGLE_INIT_FROM_REGION( ®ions[i] ); if (dfb_rectangle_intersect( &rects[n], &rect )) { points[n].x = x + rects[n].x - rect.x; points[n].y = y + rects[n].y - rect.y; n++; } } if (n > 0) { pthread_mutex_lock( ©_lock ); if (!copy_state_inited) { dfb_state_init( ©_state, NULL ); copy_state_inited = true; } copy_state.modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION; copy_state.clip.x2 = destination->config.size.w - 1; copy_state.clip.y2 = destination->config.size.h - 1; copy_state.source = source; copy_state.destination = destination; copy_state.from = from; copy_state.to = to; dfb_gfxcard_batchblit( rects, points, n, ©_state ); /* Signal end of sequence. */ dfb_state_stop_drawing( ©_state ); pthread_mutex_unlock( ©_lock ); } }
void dfb_gfx_stretch_to( CoreSurface *source, CoreSurface *destination, const DFBRectangle *srect, const DFBRectangle *drect, bool from_back ) { DFBRectangle sourcerect = { 0, 0, source->config.size.w, source->config.size.h }; DFBRectangle destrect = { 0, 0, destination->config.size.w, destination->config.size.h }; if (srect) { if (!dfb_rectangle_intersect( &sourcerect, srect )) return; } if (drect) { if (!dfb_rectangle_intersect( &destrect, drect )) return; } pthread_mutex_lock( ©_lock ); if (!copy_state_inited) { dfb_state_init( ©_state, NULL ); copy_state_inited = true; } copy_state.modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION; copy_state.clip.x2 = destination->config.size.w - 1; copy_state.clip.y2 = destination->config.size.h - 1; copy_state.source = source; copy_state.destination = destination; copy_state.from = from_back ? CSBR_BACK : CSBR_FRONT; dfb_gfxcard_stretchblit( &sourcerect, &destrect, ©_state ); /* Signal end of sequence. */ dfb_state_stop_drawing( ©_state ); pthread_mutex_unlock( ©_lock ); }
void dfb_gfx_copy_stereo( CoreSurface *source, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceStereoEye destination_eye, const DFBRectangle *rect, int x, int y, bool from_back ) { DFBRectangle sourcerect = { 0, 0, source->config.size.w, source->config.size.h }; StateClient *client = state_client_tls.Get(); D_FLAGS_SET( client->state.modified, SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO ); client->state.clip.x2 = destination->config.size.w - 1; client->state.clip.y2 = destination->config.size.h - 1; client->state.source = source; client->state.destination = destination; client->state.from = from_back ? CSBR_BACK : CSBR_FRONT; client->state.from_eye = source_eye; client->state.to = CSBR_BACK; client->state.to_eye = destination_eye; if (rect) { if (dfb_rectangle_intersect( &sourcerect, rect )) { DFBPoint point = { x + sourcerect.x - rect->x, y + sourcerect.y - rect->y }; CoreGraphicsStateClient_Blit( &client->client, &sourcerect, &point, 1 ); } } else { DFBPoint point = { x, y }; CoreGraphicsStateClient_Blit( &client->client, &sourcerect, &point, 1 ); } CoreGraphicsStateClient_Flush( &client->client, 0, CGSCFF_NONE ); /* Signal end of sequence. */ dfb_state_stop_drawing( &client->state ); client->state.destination = NULL; client->state.source = NULL; }
DFBResult dfb_surface_write_buffer( CoreSurface *surface, CoreSurfaceBufferRole role, const void *source, int pitch, const DFBRectangle *prect ) { DFBResult ret; int bytes; DFBRectangle rect; DFBSurfacePixelFormat format; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( pitch > 0 || source == NULL ); DFB_RECTANGLE_ASSERT_IF( prect ); D_DEBUG_AT( Core_Surface, "%s( %p, %p [%d] )\n", __FUNCTION__, surface, source, pitch ); /* Determine area. */ rect.x = 0; rect.y = 0; rect.w = surface->config.size.w; rect.h = surface->config.size.h; if (prect) { if (!dfb_rectangle_intersect( &rect, prect )) { D_DEBUG_AT( Core_Surface, " -> no intersection!\n" ); return DFB_INVAREA; } if (!DFB_RECTANGLE_EQUAL( rect, *prect )) { D_DEBUG_AT( Core_Surface, " -> got clipped to %d,%d-%dx%d!\n", DFB_RECTANGLE_VALS(&rect) ); return DFB_INVAREA; } } /* Calculate bytes per read line. */ format = surface->config.format; bytes = DFB_BYTES_PER_LINE( format, rect.w ); D_DEBUG_AT( Core_Surface, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect), dfb_pixelformat_name( format ) ); ret = CoreSurface_PreLockBuffer2( surface, role, CSAID_CPU, CSAF_WRITE, false, &allocation ); if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name ); /* 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 ); dfb_surface_allocation_unref( allocation ); 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; y<rect.h; y++) { if (source) { direct_memcpy( lock.addr, source, bytes ); source += pitch; } else memset( lock.addr, 0, bytes ); lock.addr += lock.pitch; } /* Unlock the allocation. */ ret = dfb_surface_pool_unlock( allocation->pool, allocation, &lock ); if (ret) D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &lock ); } } dfb_surface_allocation_unref( allocation ); return DFB_OK; }
DFBResult dfb_surface_read_buffer( CoreSurface *surface, CoreSurfaceBufferRole role, void *destination, int pitch, const DFBRectangle *prect ) { DFBResult ret; int y; int bytes; DFBRectangle rect; DFBSurfacePixelFormat format; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( destination != NULL ); D_ASSERT( pitch > 0 ); DFB_RECTANGLE_ASSERT_IF( prect ); D_DEBUG_AT( Core_Surface, "%s( %p, %p [%d] )\n", __FUNCTION__, surface, destination, pitch ); /* 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_Surface, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect), dfb_pixelformat_name( format ) ); ret = CoreSurface_PreLockBuffer2( surface, role, CSAID_CPU, CSAF_READ, false, &allocation ); if (ret == DFB_NOALLOCATION) { for (y=0; y<rect.h; y++) { memset( destination, 0, bytes ); destination += pitch; } return DFB_OK; } if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name ); /* 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 ); dfb_surface_allocation_unref( allocation ); 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; y<rect.h; y++) { direct_memcpy( destination, lock.addr, bytes ); destination += pitch; lock.addr += lock.pitch; } /* Unlock the allocation. */ ret = dfb_surface_pool_unlock( allocation->pool, allocation, &lock ); if (ret) D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &lock ); } } dfb_surface_allocation_unref( allocation ); return DFB_OK; }
static DFBResult update_screen( DFBX11 *x11, const DFBRectangle *clip, CoreSurfaceBufferLock *lock, XWindow *xw ) { void *dst; void *src; unsigned int offset = 0; XImage *ximage; CoreSurface *surface; CoreSurfaceAllocation *allocation; DFBX11Shared *shared; DFBRectangle rect; bool direct = false; D_ASSERT( x11 != NULL ); DFB_RECTANGLE_ASSERT( clip ); D_DEBUG_AT( X11_Update, "%s( %4d,%4d-%4dx%4d )\n", __FUNCTION__, DFB_RECTANGLE_VALS( clip ) ); CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); shared = x11->shared; D_ASSERT( shared != NULL ); XLockDisplay( x11->display ); if (!xw) { XUnlockDisplay( x11->display ); return DFB_OK; } allocation = lock->allocation; CORE_SURFACE_ALLOCATION_ASSERT( allocation ); surface = allocation->surface; D_ASSERT( surface != NULL ); rect.x = rect.y = 0; rect.w = xw->width; rect.h = xw->height; if (!dfb_rectangle_intersect( &rect, clip )) { XUnlockDisplay( x11->display ); return DFB_OK; } D_DEBUG_AT( X11_Update, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &rect ) ); #ifdef USE_GLX /* Check for GLX allocation... */ if (allocation->pool == shared->glx_pool && lock->handle) { LocalPixmap *pixmap = lock->handle; D_MAGIC_ASSERT( pixmap, LocalPixmap ); /* ...and just call SwapBuffers... */ //D_DEBUG_AT( X11_Update, " -> Calling glXSwapBuffers( 0x%lx )...\n", alloc->drawable ); //glXSwapBuffers( x11->display, alloc->drawable ); D_DEBUG_AT( X11_Update, " -> Copying from GLXPixmap...\n" ); glXWaitGL(); XCopyArea( x11->display, pixmap->pixmap, xw->window, xw->gc, rect.x, rect.y, rect.w, rect.h, rect.x, rect.y ); glXWaitX(); XUnlockDisplay( x11->display ); return DFB_OK; } #endif /* Check for our special native allocation... */ if (allocation->pool == shared->x11image_pool && lock->handle) { x11Image *image = lock->handle; D_MAGIC_ASSERT( image, x11Image ); /* ...and directly XShmPutImage from that. */ ximage = image->ximage; direct = true; } else { /* ...or copy or convert into XShmImage or XImage allocated with the XWindow. */ ximage = xw->ximage; offset = xw->ximage_offset; xw->ximage_offset = (offset ? 0 : ximage->height / 2); /* make sure the 16-bit input formats are properly 2-pixel-clipped */ switch (surface->config.format) { case DSPF_I420: case DSPF_YV12: case DSPF_NV12: case DSPF_NV21: if (rect.y & 1) { rect.y--; rect.h++; } /* fall through */ case DSPF_YUY2: case DSPF_UYVY: case DSPF_NV16: if (rect.x & 1) { rect.x--; rect.w++; } default: /* no action */ break; } dst = xw->virtualscreen + rect.x * xw->bpp + (rect.y + offset) * ximage->bytes_per_line; src = lock->addr + DFB_BYTES_PER_LINE( surface->config.format, rect.x ) + rect.y * lock->pitch; switch (xw->depth) { case 32: dfb_convert_to_argb( surface->config.format, src, lock->pitch, surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h ); break; case 24: dfb_convert_to_rgb32( surface->config.format, src, lock->pitch, surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h ); break; case 16: if (surface->config.format == DSPF_LUT8) { int width = rect.w; int height = rect.h; const u8 *src8 = src; u16 *dst16 = dst; CorePalette *palette = surface->palette; int x; while (height--) { for (x=0; x<width; x++) { DFBColor color = palette->entries[src8[x]]; dst16[x] = PIXEL_RGB16( color.r, color.g, color.b ); } src8 += lock->pitch; dst16 += ximage->bytes_per_line / 2; } } else { dfb_convert_to_rgb16( surface->config.format, src, lock->pitch, surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h ); } break; case 15: dfb_convert_to_rgb555( surface->config.format, src, lock->pitch, surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h ); break; default: D_ONCE( "unsupported depth %d", xw->depth ); } } D_ASSERT( ximage != NULL ); /* Wait for previous data to be processed... */ XSync( x11->display, False ); /* ...and immediately queue or send the next! */ if (x11->use_shm) { /* Just queue the command, it's XShm :) */ XShmPutImage( xw->display, xw->window, xw->gc, ximage, rect.x, rect.y + offset, rect.x, rect.y, rect.w, rect.h, False ); /* Make sure the queue has really happened! */ XFlush( x11->display ); } else /* Initiate transfer of buffer... */ XPutImage( xw->display, xw->window, xw->gc, ximage, rect.x, rect.y + offset, rect.x, rect.y, rect.w, rect.h ); /* Wait for display if single buffered and not converted... */ if (direct && !(surface->config.caps & DSCAPS_FLIPPING)) XSync( x11->display, False ); XUnlockDisplay( x11->display ); return DFB_OK; }
void dfb_gfx_copy_regions_client( CoreSurface *source, CoreSurfaceBufferRole from, DFBSurfaceStereoEye source_eye, CoreSurface *destination, CoreSurfaceBufferRole to, DFBSurfaceStereoEye destination_eye, const DFBRegion *regions, unsigned int num, int x, int y, CoreGraphicsStateClient *_client ) { unsigned int i, n = 0; DFBRectangle rect = { 0, 0, source->config.size.w, source->config.size.h }; DFBRectangle rects[num]; DFBPoint points[num]; CoreGraphicsStateClient *client = _client ? _client : &state_client_tls.Get()->client; CardState *state = client->state; CardState backup; for (i=0; i<num; i++) { DFB_REGION_ASSERT( ®ions[i] ); rects[n] = DFB_RECTANGLE_INIT_FROM_REGION( ®ions[i] ); if (dfb_rectangle_intersect( &rects[n], &rect )) { points[n].x = x + rects[n].x; points[n].y = y + rects[n].y; n++; } } if (n > 0) { backup.clip = state->clip; backup.source = state->source; backup.destination = state->destination; backup.from = state->from; backup.from_eye = state->from_eye; backup.to = state->to; backup.to_eye = state->to_eye; backup.blittingflags = state->blittingflags; D_FLAGS_SET( state->modified, SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO | SMF_BLITTING_FLAGS ); state->clip.x1 = 0; state->clip.y1 = 0; state->clip.x2 = destination->config.size.w - 1; state->clip.y2 = destination->config.size.h - 1; state->source = source; state->destination = destination; state->from = from; state->from_eye = source_eye; state->to = to; state->to_eye = destination_eye; state->blittingflags = DSBLIT_NOFX; CoreGraphicsStateClient_Blit( client, rects, points, n ); if (!_client) CoreGraphicsStateClient_Flush( client, 0, CGSCFF_NONE ); D_FLAGS_SET( state->modified, SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO | SMF_BLITTING_FLAGS ); state->clip = backup.clip; state->source = backup.source; state->destination = backup.destination; state->from = backup.from; state->from_eye = backup.from_eye; state->to = backup.to; state->to_eye = backup.to_eye; state->blittingflags = backup.blittingflags; } }
void sawman_draw_cursor ( CoreWindowStack *stack, CardState *state, CoreSurface *surface, DFBRegion *region, int x, int y ) { DFBRectangle src; DFBRectangle clip; DFBSurfaceBlittingFlags flags = DSBLIT_BLEND_ALPHACHANNEL; D_ASSERT( stack != NULL ); D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( region ); D_ASSUME( stack->cursor.opacity > 0 ); D_DEBUG_AT( SaWMan_Draw, "%s( %p, %d,%d-%dx%d )\n", __FUNCTION__, stack, DFB_RECTANGLE_VALS_FROM_REGION( region ) ); /* Initialize source rectangle. */ src.x = region->x1 - x + stack->cursor.hot.x; src.y = region->y1 - y + stack->cursor.hot.y; src.w = region->x2 - region->x1 + 1; src.h = region->y2 - region->y1 + 1; D_DEBUG_AT( SaWMan_Draw, " -> cursor surface %p\n", stack->cursor.surface ); /* Initialize source clipping rectangle */ clip.x = clip.y = 0; clip.w = stack->cursor.surface->config.size.w; clip.h = stack->cursor.surface->config.size.h; /* Intersect rectangles */ if (!dfb_rectangle_intersect( &src, &clip )) return; /* Set destination. */ if (surface) { state->destination = surface; state->modified |= SMF_DESTINATION; } /* Use global alpha blending. */ if (stack->cursor.opacity != 0xFF) { flags |= DSBLIT_BLEND_COLORALPHA; if (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED) { /* Need to premultiply source with Ac? */ flags |= DSBLIT_SRC_PREMULTCOLOR; dfb_state_set_src_blend( state, DSBF_ONE ); } else dfb_state_set_src_blend( state, DSBF_SRCALPHA ); /* Set opacity as blending factor. */ if (state->color.a != stack->cursor.opacity) { state->color.a = stack->cursor.opacity; state->modified |= SMF_COLOR; } } /* Different compositing methods depending on destination format. */ if (flags & DSBLIT_BLEND_ALPHACHANNEL) { if (DFB_PIXELFORMAT_HAS_ALPHA( state->destination->config.format )) { /* * Always use compliant Porter/Duff SRC_OVER, * if the destination has an alpha channel. * * Cd = destination color (non-premultiplied) * Ad = destination alpha * * Cs = source color (non-premultiplied) * As = source alpha * * Ac = color alpha * * cd = Cd * Ad (premultiply destination) * cs = Cs * As (premultiply source) * * The full equation to calculate resulting color and alpha (premultiplied): * * cx = cd * (1-As*Ac) + cs * Ac * ax = Ad * (1-As*Ac) + As * Ac */ dfb_state_set_src_blend( state, DSBF_ONE ); /* Need to premultiply source with As*Ac or only with Ac? */ if (! (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED)) flags |= DSBLIT_SRC_PREMULTIPLY; else if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; /* Need to premultiply/demultiply destination? */ // if (! (state->destination->caps & DSCAPS_PREMULTIPLIED)) // flags |= DSBLIT_DST_PREMULTIPLY | DSBLIT_DEMULTIPLY; } else { /* * We can avoid DSBLIT_SRC_PREMULTIPLY for destinations without an alpha channel * by using another blending function, which is more likely that it's accelerated * than premultiplication at this point in time. * * This way the resulting alpha (ax) doesn't comply with SRC_OVER, * but as the destination doesn't have an alpha channel it's no problem. * * As the destination's alpha value is always 1.0 there's no need for * premultiplication. The resulting alpha value will also be 1.0 without * exceptions, therefore no need for demultiplication. * * cx = Cd * (1-As*Ac) + Cs*As * Ac (still same effect as above) * ax = Ad * (1-As*Ac) + As*As * Ac (wrong, but discarded anyways) */ if (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED) { /* Need to premultiply source with Ac? */ if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; dfb_state_set_src_blend( state, DSBF_ONE ); } else dfb_state_set_src_blend( state, DSBF_SRCALPHA ); } } /* Set blitting flags. */ dfb_state_set_blitting_flags( state, flags ); /* Set blitting source. */ state->source = stack->cursor.surface; state->from_eye = DSSE_LEFT; state->modified |= SMF_SOURCE | SMF_FROM; /* Set clipping region. */ dfb_state_set_clip( state, region ); /* Blit from the window to the region being updated. */ DFBPoint point = { region->x1, region->y1 }; D_DEBUG_AT( SaWMan_Draw, " -> client %p\n", state->client ); CoreGraphicsStateClient_Blit( state->client, &src, &point, 1 ); /* Reset blitting source. */ state->source = NULL; state->modified |= SMF_SOURCE; /* Reset destination. */ if (surface) { state->destination = NULL; state->modified |= SMF_DESTINATION; } }