bool initBackgroundLayer( BACKGROUND_LAYER_T *bg, uint16_t colour, int32_t layer) { int result = 0; VC_IMAGE_TYPE_T type = VC_IMAGE_RGBA16; uint32_t vc_image_ptr; bg->resource = vc_dispmanx_resource_create(type, 1, 1, &vc_image_ptr); if(!bg->resource) return false; //--------------------------------------------------------------------- VC_RECT_T dst_rect; vc_dispmanx_rect_set(&dst_rect, 0, 0, 1, 1); bg->layer = layer; result = vc_dispmanx_resource_write_data(bg->resource, type, sizeof(colour), &colour, &dst_rect); if(result != DISPMANX_SUCCESS){ result = vc_dispmanx_resource_delete(bg->resource); return false; } return true; }
void vsync(DISPMANX_UPDATE_HANDLE_T u, void* arg) { int ret; DISPMANX_UPDATE_HANDLE_T update; update = vc_dispmanx_update_start( 10 ); assert( update ); ret = vc_dispmanx_element_change_source( update, element, resource[next_resource]); assert( ret == 0 ); ret = vc_dispmanx_update_submit_sync( update ); assert( ret == 0 ); if(next_resource != 2) { int real_next_resource = next_resource ^ 1; next_resource = 2; // use filler if next callback called before this one ends // fill image int n; for (n=0; n<HEIGHT; n+=2) { get_packet(ROW(n)+24); // +24 because clock never changes memcpy(ROW(n+1)+24, ROW(n)+24, 336); // double it up because the hardware scaler // will introduce blurring between lines } // write to resource ret = vc_dispmanx_resource_write_data( resource[real_next_resource], TYPE, PITCH, image, &image_rect ); assert( ret == 0 ); next_resource = real_next_resource; // queue up next real resource } }
void iterateLife( LIFE_T *life) { memcpy(life->field, life->fieldNext, life->fieldLength); if (life->numberOfThreads == 0) { iterateLifeKernel(life, 0); } else { pthread_barrier_wait(&(life->startIterationBarrier)); pthread_barrier_wait(&(life->finishedIterationBarrier)); } int result = 0; VC_IMAGE_TYPE_T type = VC_IMAGE_RGBA16; result = vc_dispmanx_resource_write_data(life->backResource, type, life->pitch, life->buffer, &(life->bmpRect)); assert(result == 0); }
static int DISPMANX_FlipHWSurface(_THIS, SDL_Surface *surface) { /*if ( switched_away ) { return -2; // no hardware access }*/ //Volcamos desde el ram bitmap buffer al dispmanx resource buffer //que toque. cada vez a uno. vc_dispmanx_resource_write_data( dispvars->resources[flip_page], dispvars->pix_format, dispvars->pitch, dispvars->pixmem, &(dispvars->bmp_rect) ); //**Empieza actualización*** dispvars->update = vc_dispmanx_update_start( 0 ); vc_dispmanx_element_change_source(dispvars->update, dispvars->element, dispvars->resources[flip_page]); vc_dispmanx_update_submit_sync( dispvars->update ); //vc_dispmanx_update_submit(dispvars->update, NULL, NULL); //**Acaba actualización*** flip_page = !flip_page; //MAC Esto no hace falta porque SDL siempre escribe en dispvars->pixmem, //que es el buffer en RAM y que copiamos cada vez a un resource. //surface->pixels = flip_address[flip_page]; return (0); }
static void dispmanx_surface_update(void *data, const void *frame, struct dispmanx_surface *surface) { struct dispmanx_video *_dispvars = data; struct dispmanx_page *page = NULL; /* Wait until last issued flip completes to get a free page. Also, dispmanx doesn't support issuing more than one pageflip.*/ slock_lock(_dispvars->pending_mutex); if (_dispvars->pageflip_pending > 0) { scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex); } slock_unlock(_dispvars->pending_mutex); page = dispmanx_get_free_page(_dispvars, surface); /* Frame blitting */ vc_dispmanx_resource_write_data(page->resource, surface->pixformat, surface->pitch, (void*)frame, &(surface->bmp_rect)); /* Issue a page flip that will be done at the next vsync. */ _dispvars->update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(_dispvars->update, surface->element, page->resource); vc_dispmanx_update_submit(_dispvars->update, dispmanx_vsync_callback, (void*)page); slock_lock(_dispvars->pending_mutex); _dispvars->pageflip_pending++; slock_unlock(_dispvars->pending_mutex); }
static void DISPMANX_BlankBackground(void) { //MAC: Funcion que simplemente pone un element nuevo cuyo resource es de un solo pixel de color negro, //se escala a pantalla completa y listo. // we create a 1x1 black pixel image that is added to display just behind video VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565; uint32_t vc_image_ptr; uint16_t image = 0x0000; // black VC_RECT_T dst_rect, src_rect; dispvars->b_resource = vc_dispmanx_resource_create( type, 1 /*width*/, 1 /*height*/, &vc_image_ptr ); vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1); vc_dispmanx_resource_write_data( dispvars->b_resource, type, sizeof(image), &image, &dst_rect ); vc_dispmanx_rect_set( &src_rect, 0, 0, 1<<16, 1<<16); vc_dispmanx_rect_set( &dst_rect, 0, 0, 0, 0); dispvars->b_update = vc_dispmanx_update_start(0); dispvars->b_element = vc_dispmanx_element_add(dispvars->b_update, dispvars->display, -1 /*layer*/, &dst_rect, dispvars->b_resource, &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, (DISPMANX_TRANSFORM_T)0 ); vc_dispmanx_update_submit_sync( dispvars->b_update ); }
ViewBackend::Cursor::Cursor(WPE::LibinputServer::Client& targetClient, DISPMANX_DISPLAY_HANDLE_T displayHandle, uint32_t displayWidth, uint32_t displayHeight) : targetClient(targetClient) , position({ 0, 0 }) , displaySize({ displayWidth, displayHeight }) { static VC_DISPMANX_ALPHA_T alpha = { static_cast<DISPMANX_FLAGS_ALPHA_T>(DISPMANX_FLAGS_ALPHA_FROM_SOURCE), 255, 0 }; DISPMANX_UPDATE_HANDLE_T updateHandle = vc_dispmanx_update_start(0); uint32_t imagePtr; VC_RECT_T rect; vc_dispmanx_rect_set(&rect, 0, 0, CursorData::width, CursorData::height); DISPMANX_RESOURCE_HANDLE_T pointerResource = vc_dispmanx_resource_create(VC_IMAGE_RGBA32, CursorData::width, CursorData::height, &imagePtr); vc_dispmanx_resource_write_data(pointerResource, VC_IMAGE_RGBA32, CursorData::width * 4, CursorData::data, &rect); VC_RECT_T srcRect, destRect; vc_dispmanx_rect_set(&srcRect, 0, 0, CursorData::width << 16, CursorData::height << 16); vc_dispmanx_rect_set(&destRect, position.first, position.second, cursorWidth, cursorHeight); cursorHandle = vc_dispmanx_element_add(updateHandle, displayHandle, 10, &destRect, pointerResource, &srcRect, DISPMANX_PROTECTION_NONE, &alpha, nullptr, DISPMANX_NO_ROTATE); vc_dispmanx_resource_delete(pointerResource); vc_dispmanx_update_submit_sync(updateHandle); }
static void DISPMANX_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) { //En OpenGL también va así. No deberíamos esperar para cambiar el buffer, de hecho la aplicación //piensa que no hay doble buffer (hasta hemos desactivado el double buffer), sino que en lugar //de esperar, simplemente deberíamos actualizar la superficie visible directamente... Pero no //puedo hacer eso porque no tengo acceso a la superficie visible: tengo la superficie de vídeo en RAM //y cada vez que se hace un cambio (o sea, cada vez que llego aquí) copio esa superficie a la VRAM //y espero a cambiar los buffers para no tener tearing, a pesar de que esta función se supone que no //hace eso. Pero en OpenGL se hace lo mismo ya que la única manera de mostrar los cambios es hacer //un GL_SWAP_BUFFERS que también es bloqueante. //Volcamos desde el ram bitmap buffer al dispmanx resource buffer que toque. cada vez a uno. vc_dispmanx_resource_write_data( dispvars->resources[flip_page], dispvars->pix_format, dispvars->pitch, dispvars->pixmem, &(dispvars->bmp_rect) ); //Empieza actualización dispvars->update = vc_dispmanx_update_start( 0 ); vc_dispmanx_element_change_source(dispvars->update, dispvars->element, dispvars->resources[flip_page]); vc_dispmanx_update_submit_sync( dispvars->update ); //vc_dispmanx_update_submit(dispvars->update, NULL, NULL); //Acaba actualización flip_page = !flip_page; return; }
void vo_display_frame (RECT_VARS_T* vars, int width, int height, int chroma_width, int chroma_height, uint8_t * const * buf, int num) { int ret; static VC_RECT_T src_rect; static VC_RECT_T dst_rect; static VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, /*alpha 0->255*/ 0 }; int pitch = VO_ALIGN_UP(width,32); assert((height % 16) == 0); assert((chroma_height % 16) == 0); if (num == 0) { vars->resource = vc_dispmanx_resource_create( VC_IMAGE_YUV420, width, height, &vars->vc_image_ptr ); assert( vars->resource ); vars->update = vc_dispmanx_update_start( 10 ); assert( vars->update ); vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 ); vc_dispmanx_rect_set( &dst_rect, 0, 0, vars->info.width, vars->info.height); vars->element = vc_dispmanx_element_add( vars->update, vars->display, 2000, // layer &dst_rect, vars->resource, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, // clamp VC_IMAGE_ROT0 ); ret = vc_dispmanx_update_submit( vars->update, NULL, NULL); vc_dispmanx_rect_set( &dst_rect, 0, 0, width, (3*height)/2); } ret = vc_dispmanx_resource_write_data( vars->resource, VC_IMAGE_YUV420, pitch, buf[0], &dst_rect ); assert( ret == 0 ); vars->update = vc_dispmanx_update_start( 10 ); assert( vars->update ); //ret = vc_dispmanx_update_submit_sync( vars->update ); ret = vc_dispmanx_update_submit( vars->update, NULL, NULL); assert( ret == 0 ); }
static void dmx_region_update(struct dmx_region_t *dmx_region, DISPMANX_UPDATE_HANDLE_T update, picture_t *picture) { vc_dispmanx_resource_write_data(dmx_region->resource, VC_IMAGE_RGBA32, picture->p[0].i_pitch, picture->p[0].p_pixels, &dmx_region->bmp_rect); vc_dispmanx_element_change_source(update, dmx_region->element, dmx_region->resource); dmx_region->picture = picture; }
static void show_cursor(ALLEGRO_DISPLAY_RASPBERRYPI *d) { if (d->cursor_data == NULL || cursor_added) { return; } int width = d->cursor_width; int height = d->cursor_height; uint32_t unused; cursor_resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, width, height, &unused); VC_RECT_T r; r.x = 0; r.y = 0; r.width = width; r.height = height; int dpitch = pot(sizeof(uint32_t) * width); dispman_update = vc_dispmanx_update_start(0); vc_dispmanx_resource_write_data(cursor_resource, VC_IMAGE_ARGB8888, dpitch, d->cursor_data, &r); vc_dispmanx_update_submit_sync(dispman_update); ALLEGRO_MOUSE_STATE state; al_get_mouse_state(&state); dst_rect.x = state.x+d->cursor_offset_x; dst_rect.y = state.y+d->cursor_offset_y; dst_rect.width = width; dst_rect.height = height; src_rect.x = 0; src_rect.y = 0; src_rect.width = width << 16; src_rect.height = height << 16; dispman_update = vc_dispmanx_update_start(0); cursor_element = vc_dispmanx_element_add( dispman_update, dispman_display, 0/*layer*/, &dst_rect, cursor_resource, &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/ ); vc_dispmanx_update_submit_sync(dispman_update); cursor_added = true; }
static void DISPMANX_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) { //Esto es una solución temporal! no puedo volcar el bitmap buffer //entero cada vez que quiero actualizar un área de pantalla! //En resoluciones internas bajas no se nota, pero en altas... vc_dispmanx_resource_write_data( dispvars->resources[flip_page], dispvars->pix_format, dispvars->pitch, dispvars->pixmem, &(dispvars->bmp_rect) ); return; }
int SliceMngr::loadSlice(const char *pFilename){ if (loadPng(&(mImage.image), pFilename) == false){ printf("failed to load\n"); return -1; }else{ vc_dispmanx_resource_write_data(mImage.resource, mImage.image.type, mImage.image.pitch, mImage.image.buffer, &(mImage.dstRect)); } return 0; }
NativeResource::NativeResource(unsigned int x, unsigned int y, unsigned int w, unsigned int h, VC_IMAGE_TYPE_T type, void * _imageData, int _imagePitch) : resourceHandle(0), rgbType(type), nativeImageHandle(0), imageData(_imageData ), imagePitch(_imagePitch) { int ret; setRegion(x,y,w,h); resourceHandle = vc_dispmanx_resource_create( rgbType, region.width, region.height, &nativeImageHandle ); ret = vc_dispmanx_resource_write_data( resourceHandle, rgbType, imagePitch, imageData, ®ion ); if ( ret != 0 ) throw runtime_error("runtime error : NativeResource::NativeResource ** resourceWriteData failed."); }
static void frontend_display(void) { VC_RECT_T dst_rect; vc_dispmanx_rect_set( &dst_rect, 0, 0, 640, 480 ); // begin display update fe_update = vc_dispmanx_update_start( 0 ); // blit image to the current resource vc_dispmanx_resource_write_data( fe_resource, VC_IMAGE_RGB565, 640*2, fe_screen, &dst_rect ); vc_dispmanx_update_submit_sync( fe_update ); }
void FE_DisplayScreen(void) { VC_RECT_T dst_rect; vc_dispmanx_rect_set( &dst_rect, 0, 0, surface_width, surface_height ); vc_dispmanx_resource_write_data( cur_res, VC_IMAGE_RGB565, surface_width*2, gp2x_screen15, &dst_rect ); dispman_update = vc_dispmanx_update_start( 0 ); vc_dispmanx_element_change_source( dispman_update, dispman_element, cur_res ); vc_dispmanx_update_submit( dispman_update, 0, 0 ); // swap current resource tmp_res = cur_res; cur_res = prev_res; prev_res = tmp_res; }
/* Create a cursor from a surface */ static SDL_Cursor * RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) { RPI_CursorData *curdata; SDL_Cursor *cursor; int ret; VC_RECT_T dst_rect; Uint32 dummy; SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888); SDL_assert(surface->pitch == surface->w * 4); cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor)); if (cursor == NULL) { SDL_OutOfMemory(); return NULL; } curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata)); if (curdata == NULL) { SDL_OutOfMemory(); SDL_free(cursor); return NULL; } curdata->hot_x = hot_x; curdata->hot_y = hot_y; curdata->w = surface->w; curdata->h = surface->h; /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */ curdata->resource = vc_dispmanx_resource_create( VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy ); SDL_assert(curdata->resource); vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h); /* A note from Weston: * vc_dispmanx_resource_write_data() ignores ifmt, * rect.x, rect.width, and uses stride only for computing * the size of the transfer as rect.height * stride. * Therefore we can only write rows starting at x=0. */ ret = vc_dispmanx_resource_write_data( curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect ); SDL_assert ( ret == DISPMANX_SUCCESS ); cursor->driverdata = curdata; return cursor; }
void writeDataWorms( WORMS_T *worms) { VC_RECT_T dst_rect; vc_dispmanx_rect_set(&dst_rect, 0, 0, worms->image.width, worms->image.height); int result = vc_dispmanx_resource_write_data(worms->backResource, worms->image.type, worms->image.pitch, worms->image.buffer, &dst_rect); assert(result == 0); }
static void dispmanx_update_main(void *data, const void *frame) { struct dispmanx_page *page = NULL; struct dispmanx_video *_dispvars = data; if (!_dispvars) return; page = dispmanx_get_free_page(_dispvars); if (!page) return; /* Frame blitting */ vc_dispmanx_resource_write_data(_dispvars->resources[page->numpage], _dispvars->pixFormat, _dispvars->pitch, (void *)frame, &(_dispvars->bmpRect)); /* Issue flipping: we send the page * to the dispmanx API internal flipping FIFO stack. */ dispmanx_flip (page, _dispvars); }
static struct dmx_region_t *dmx_region_new(vout_display_t *vd, DISPMANX_UPDATE_HANDLE_T update, subpicture_region_t *region) { vout_display_sys_t *sys = vd->sys; video_format_t *fmt = ®ion->fmt; struct dmx_region_t *dmx_region = malloc(sizeof(struct dmx_region_t)); uint32_t image_handle; dmx_region->pos_x = region->i_x; dmx_region->pos_y = region->i_y; vc_dispmanx_rect_set(&dmx_region->bmp_rect, 0, 0, fmt->i_visible_width, fmt->i_visible_height); vc_dispmanx_rect_set(&dmx_region->src_rect, 0, 0, fmt->i_visible_width << 16, fmt->i_visible_height << 16); vc_dispmanx_rect_set(&dmx_region->dst_rect, region->i_x, region->i_y, fmt->i_visible_width, fmt->i_visible_height); dmx_region->resource = vc_dispmanx_resource_create(VC_IMAGE_RGBA32, dmx_region->bmp_rect.width | (region->p_picture->p[0].i_pitch << 16), dmx_region->bmp_rect.height | (dmx_region->bmp_rect.height << 16), &image_handle); vc_dispmanx_resource_write_data(dmx_region->resource, VC_IMAGE_RGBA32, region->p_picture->p[0].i_pitch, region->p_picture->p[0].p_pixels, &dmx_region->bmp_rect); dmx_region->alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_MIX; dmx_region->alpha.opacity = region->i_alpha; dmx_region->alpha.mask = DISPMANX_NO_HANDLE; dmx_region->element = vc_dispmanx_element_add(update, sys->dmx_handle, sys->layer + 1, &dmx_region->dst_rect, dmx_region->resource, &dmx_region->src_rect, DISPMANX_PROTECTION_NONE, &dmx_region->alpha, NULL, VC_IMAGE_ROT0); dmx_region->next = NULL; dmx_region->picture = region->p_picture; return dmx_region; }
static void dispmanx_set_texture_frame(void *data, const void *frame, bool rgb32, unsigned width, unsigned height, float alpha) { struct dispmanx_video *_dispvars = data; if (!_dispvars) return; /* If we're entering the menu in this frame, * we must setup rects, resources and menu element. */ if (width != _dispvars->menu_width || height != _dispvars->menu_height) { int i, dst_width, dst_ypos; VC_DISPMANX_ALPHA_T layerAlpha; /* Sanity check */ if (width == 0 || height == 0) return; _dispvars->menu_width = width; _dispvars->menu_height = height; _dispvars->menu_pitch = width * (rgb32 ? 4 : 2); _dispvars->menu_pixFormat = VC_IMAGE_RGBA16; _dispvars->menu_flip_page = 0; /* Transparency disabled */ layerAlpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; #if 0 layerAlpha.opacity = (unsigned char)(255.0f * alpha); #endif layerAlpha.opacity = 210; layerAlpha.mask = 0; _dispvars->menu_alpha = &layerAlpha; dst_width = _dispvars->amode.height * _dispvars->aspect; /* If we obtain a scaled image width that is * bigger than the physical screen width, * then we keep the physical screen width as our maximun width. */ #if 0 if (dst_width > _dispvars->amode.width) dst_width = _dispvars->amode.width; #endif dst_ypos = (_dispvars->amode.width - dst_width) / 2; vc_dispmanx_rect_set(&(_dispvars->menu_dstRect), dst_ypos, 0, dst_width, _dispvars->amode.height); /* We configure the rects now. */ vc_dispmanx_rect_set(&(_dispvars->menu_bmpRect), 0, 0, _dispvars->menu_width, _dispvars->menu_height); vc_dispmanx_rect_set(&(_dispvars->menu_srcRect), 0, 0, _dispvars->menu_width << 16, _dispvars->menu_height << 16); /* We create two resources for the menu element. */ _dispvars->menu_resources[0] = vc_dispmanx_resource_create(_dispvars->menu_pixFormat, _dispvars->menu_width, _dispvars->menu_height, &(_dispvars->vcImagePtr)); _dispvars->menu_resources[1] = vc_dispmanx_resource_create(_dispvars->menu_pixFormat, _dispvars->menu_width, _dispvars->menu_height, &(_dispvars->vcImagePtr)); /* Add the menu element. */ _dispvars->update = vc_dispmanx_update_start(0); _dispvars->menu_element = vc_dispmanx_element_add(_dispvars->update, _dispvars->display, 0, &(_dispvars->menu_dstRect), _dispvars->menu_resources[0], &(_dispvars->menu_srcRect), DISPMANX_PROTECTION_NONE, _dispvars->menu_alpha, 0, (DISPMANX_TRANSFORM_T)0); vc_dispmanx_update_submit_sync(_dispvars->update); } /* Flipping is done in every frame, * in the gfx_frame function. * That's why why change flip page here instead. */ _dispvars->menu_flip_page = !_dispvars->menu_flip_page; /* Frame blitting. */ vc_dispmanx_resource_write_data(_dispvars->menu_resources[_dispvars->menu_flip_page], _dispvars->menu_pixFormat, _dispvars->menu_pitch, (void *)frame, &(_dispvars->menu_bmpRect)); /* We don't flip the menu buffers here: * that's done in the gfx_frame function when menu is active. */ }
void initWorms( uint16_t number, uint16_t length, WORMS_T *worms, VC_IMAGE_TYPE_T imageType, DISPMANX_MODEINFO_T *info) { initImage(&(worms->image), imageType, info->width, info->height, false); srand(time(NULL)); worms->size = number; worms->worms = malloc(worms->size * sizeof(WORM_T)); if (worms->worms == NULL) { fprintf(stderr, "worms: memory exhausted\n"); exit(EXIT_FAILURE); } uint16_t i = 0; for (i = 0 ; i < worms->size ; i++) { WORM_T *worm = &(worms->worms[i]); initWorm(i, number, length, worm, &(worms->image)); } //--------------------------------------------------------------------- uint32_t vc_image_ptr; worms->frontResource = vc_dispmanx_resource_create( worms->image.type, worms->image.width |(worms->image.pitch << 16), worms->image.height | (worms->image.alignedHeight << 16), &vc_image_ptr); assert(worms->frontResource != 0); worms->backResource = vc_dispmanx_resource_create(worms->image.type, worms->image.width | (worms->image.pitch << 16), worms->image.height | (worms->image.alignedHeight << 16), &vc_image_ptr); assert(worms->backResource != 0); //--------------------------------------------------------------------- int result = 0; VC_RECT_T dst_rect; vc_dispmanx_rect_set(&dst_rect, 0, 0, worms->image.width, worms->image.height); result = vc_dispmanx_resource_write_data(worms->frontResource, worms->image.type, worms->image.pitch, worms->image.buffer, &dst_rect); assert(result == 0); }
/** * Process a single frame. * * Currently this converts the RGB image from the camera * to the BGR format expected by OpenCV, then displays * the image using OpenCV. In the future, image processing * will happen here. * * This does not have to be a global function; it could also * be put inline as a lambda function. * * @param frame the frame to be processed. */ void process_frame(cv::Mat frame) { ++n; cv::Mat_<cv::Vec3b> hsv(frame.size()); cv::Mat_<unsigned char> binary(frame.size()); cv::Mat_<unsigned char> back(frame.size()); cv::Mat_<cv::Vec3b> disp(frame.size()); cv::cvtColor(frame, hsv, CV_RGB2HSV_FULL); frame.copyTo(disp); //cv::cvtColor(frame, disp, CV_RGB2BGR); //int min[] = {hue-range, 0, 0}; //int max[] = {hue+range, 255, 255}; /* cv::inRange(hsv, cv::Scalar(hue-range, s_min, v_min), cv::Scalar(hue+range, s_max, v_max), binary); */ int numP = 0; if(done_hist) { cv::calcBackProject(&hsv, 1, channels, hist, binary, ranges, 1); cv::calcBackProject(&hsv, 1, channels, back_hist, back, ranges, 1); //cv::inRange(binary, 150, 255, binary); //cv::morphologyEx(binary, binary, cv::MORPH_CLOSE, getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(20, 20))); //cv::close(binary, binary, getStructuringElement(MORPH_ELLIPSE, cv::Size(2*10+1, 2*10+1), cv::Point(10, 10))); float centroid_x = 0.0f; float centroid_y = 0.0f; for(int j = 0; j < frame.rows; ++j) { for(int i = 0; i < frame.cols; ++i) { float weight = binary(j, i); float back_weight = back(j, i); if(weight > back_weight * (threshold / 500.0f)) { binary(j, i) = 255; //if(weight > 200) { numP += weight; centroid_x += i * weight; centroid_y += j * weight; } else { binary(j, i) = 0; } } } centroid_x /= numP; centroid_y /= numP; cv::circle(disp, cv::Point((int)centroid_x, (int)centroid_y), 5, cv::Scalar(255, 0, 0), -1); float r = sqrt(centroid_x*centroid_x + centroid_y*centroid_y); } /* cv::Mat hue(frame.size(), CV_8U); const int fromto[] = {0, 0}; cv::mixChannels(&frame, 1, &hue, 1, fromto, 1); cv::Mat binary(frame.size(), CV_8U); cv::inRange(frame, 0, 50, binary); */ //cv::Mat_<unsigned char> binary = cv::Mat_<unsigned char>::zeros(frame.rows, frame.cols); /* for(int j = 0; j < frame.rows; ++j) { for(int i = 0; i < frame.cols; ++i) { int r = frame.at<cv::Vec3b>(j, i)[0]; int b = frame.at<cv::Vec3b>(j, i)[1]; int g = frame.at<cv::Vec3b>(j, i)[2]; binary(j, i) = r - r*(b + g)/(2*255); float r = frame.at<cv::Vec3b>(j, i)[0]/255.0f; float b = frame.at<cv::Vec3b>(j, i)[1]/255.0f; float g = frame.at<cv::Vec3b>(j, i)[2]/255.0f; float h = 0; if(r>=g) { if(g>=b) { h = 60*(2-(g-b)/(r-b)); } else { 60*(4-(g-r)/(b-r)); } } else { } if(r>=g && g>=b) h = 60*(2-(g-b)/(r-b)); else if(g>r && r>=b) h = 60*(2-(r-b)/(g-b)); else if(g>=b && b>r) h = 60*(2+(b-r)/(g-r)); else if(b>g && g>r) h = 60*(4-(g-r)/(b-r)); else if(b>r && r>=g) h = 60*(4+(r-g)/(b-g)); else if(r>=b && b>g) h = 60*(6-(b-g)/(r-g)); h *= 255.0f/360.0f; //binary(j, i) = target - (unsigned char)h; if( (target -(unsigned char)h) < 10 || ((unsigned char)h - target) < 10) { binary(j, i) = 255; } else { binary(j, i) = 0; } } } */ /* cv::Mat blurred(binary.size(), CV_8U); cv::GaussianBlur(binary, blurred, cv::Size(9, 9), 2, 2); std::vector<cv::Vec3f> circles; cv::HoughCircles(blurred, circles, CV_HOUGH_GRADIENT, 2, frame.rows, 30, 100, 5, 100); for(size_t i = 0; i < circles.size(); ++i) { cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); cv::circle(disp, center, 5, cv::Scalar(0, 255, 0), -1, 8, 0); //cv::circle(frame, center, radius, cv::Scalar(0), 3, 8, 0); } */ cv::circle(disp, cv::Point(frame.size().width/2,frame.size().height/2), 25, cv::Scalar(0, 255, 0)); VC_RECT_T dst_rect; vc_dispmanx_rect_set( &dst_rect, 0, 0, 160, 120); int ret = vc_dispmanx_resource_write_data( display_resource, VC_IMAGE_RGB888, 160*3, disp.data, &dst_rect); assert(ret==0); DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start( 10 ); vc_dispmanx_element_modified(update, element, &dst_rect); vc_dispmanx_update_submit_sync(update); //cv::imshow("RPi Cam Raw", disp); //cv::imshow("RPi Cam Proc", binary); }
void flush_screen () { //SDL_UnlockSurface (prSDLScreen); if (show_inputmode) { inputmode_redraw(); } if (savestate_state == STATE_DOSAVE) { if(delay_savestate_frame > 0) --delay_savestate_frame; else { CreateScreenshot(); save_thumb(screenshot_filename); savestate_state = 0; } } unsigned long start = read_processor_time(); //if(start < next_synctime && next_synctime - start > time_per_frame - 1000) // usleep((next_synctime - start) - 1000); //SDL_Flip(prSDLScreen); if (current_resource_amigafb == 1) { current_resource_amigafb = 0; vc_dispmanx_resource_write_data( dispmanxresource_amigafb_1, VC_IMAGE_RGB565, gfxvidinfo.width * 2, gfxvidinfo.bufmem, &blit_rect ); dispmanxupdate = vc_dispmanx_update_start( 10 ); vc_dispmanx_element_change_source(dispmanxupdate,dispmanxelement,dispmanxresource_amigafb_1); vc_dispmanx_update_submit(dispmanxupdate,vsync_callback,NULL); //vc_dispmanx_update_submit_sync(dispmanxupdate); } else { current_resource_amigafb = 1; vc_dispmanx_resource_write_data( dispmanxresource_amigafb_2, VC_IMAGE_RGB565, gfxvidinfo.width * 2, gfxvidinfo.bufmem, &blit_rect ); dispmanxupdate = vc_dispmanx_update_start( 10 ); vc_dispmanx_element_change_source(dispmanxupdate,dispmanxelement,dispmanxresource_amigafb_2); vc_dispmanx_update_submit(dispmanxupdate,vsync_callback,NULL); } last_synctime = read_processor_time(); if(last_synctime - next_synctime > time_per_frame - 1000) adjust_idletime(0); else adjust_idletime(next_synctime - start); if(last_synctime - next_synctime > time_per_frame - 5000) next_synctime = last_synctime + time_per_frame * (1 + currprefs.gfx_framerate); else next_synctime = next_synctime + time_per_frame * (1 + currprefs.gfx_framerate); init_row_map(); }
static void open_screen(struct uae_prefs *p) { VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T ) (DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 255, /*alpha 0->255*/ 0 }; uint32_t vc_image_ptr; int width; int height; #ifdef PICASSO96 if (screen_is_picasso) { width = picasso_vidinfo.width; height = picasso_vidinfo.height; } else #endif { p->gfx_resolution = p->gfx_size.width > 600 ? 1 : 0; width = p->gfx_size.width; height = p->gfx_size.height; } //if(prSDLScreen != NULL) //{ // SDL_FreeSurface(prSDLScreen); // prSDLScreen = NULL; //} if(Dummy_prSDLScreen == NULL ) { const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo (); printf("DispmanX: Current resolution: %d x %d %d bpp\n",videoInfo->current_w, videoInfo->current_h, videoInfo->vfmt->BitsPerPixel); Dummy_prSDLScreen = SDL_SetVideoMode(videoInfo->current_w,videoInfo->current_h,16,SDL_SWSURFACE |SDL_FULLSCREEN); //Dummy_prSDLScreen = SDL_SetVideoMode(800,480,16,SDL_SWSURFACE ); } SDL_ShowCursor(SDL_DISABLE); // check if resolution hasn't change in menu. otherwise free the resources so that they will be re-generated with new resolution. if ((dispmanxresource_amigafb_1 != 0) && ((blit_rect.width != width) || (blit_rect.height != height) || (currprefs.gfx_correct_aspect != changed_prefs.gfx_correct_aspect))) { printf("Emulation resolution change detected.\n"); if(prSDLScreen != NULL ) { SDL_FreeSurface(prSDLScreen); prSDLScreen = 0; } graphics_dispmanshutdown(); vc_dispmanx_resource_delete( dispmanxresource_amigafb_1 ); vc_dispmanx_resource_delete( dispmanxresource_amigafb_2 ); dispmanxresource_amigafb_1 = 0; dispmanxresource_amigafb_2 = 0; } if (dispmanxresource_amigafb_1 == 0) { printf("Emulation resolution: Width %i Height: %i\n",width,height); currprefs.gfx_correct_aspect = changed_prefs.gfx_correct_aspect; prSDLScreen = SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,16, Dummy_prSDLScreen->format->Rmask, Dummy_prSDLScreen->format->Gmask, Dummy_prSDLScreen->format->Bmask, Dummy_prSDLScreen->format->Amask); dispmanxdisplay = vc_dispmanx_display_open( 0 ); vc_dispmanx_display_get_info( dispmanxdisplay, &dispmanxdinfo); dispmanxresource_amigafb_1 = vc_dispmanx_resource_create( VC_IMAGE_RGB565, width, height, &vc_image_ptr); dispmanxresource_amigafb_2 = vc_dispmanx_resource_create( VC_IMAGE_RGB565, width, height, &vc_image_ptr); vc_dispmanx_rect_set( &blit_rect, 0, 0, width,height); vc_dispmanx_resource_write_data( dispmanxresource_amigafb_1, VC_IMAGE_RGB565, width *2, prSDLScreen->pixels, &blit_rect ); vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 ); } // 16/9 to 4/3 ratio adaptation. if (currprefs.gfx_correct_aspect == 0) { // Fullscreen. vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width * 1)/100, (dispmanxdinfo.height * 2)/100 , dispmanxdinfo.width - (dispmanxdinfo.width * 2)/100 , dispmanxdinfo.height - (dispmanxdinfo.height * 4)/100 ); } else { // 4/3 shrink. vc_dispmanx_rect_set( &dst_rect, ((dispmanxdinfo.width * 13)/100) , (dispmanxdinfo.height * 2)/100 , (dispmanxdinfo.width - ((dispmanxdinfo.width * 26)/100)) , dispmanxdinfo.height - (dispmanxdinfo.height * 4)/100 ); } // For debug, in order to avoid full screen. //vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width /2), // (dispmanxdinfo.height /2) , // (dispmanxdinfo.width - (dispmanxdinfo.width * 6)/100 )/2, // (dispmanxdinfo.height - (dispmanxdinfo.height * 7)/100 )/2); if (DispManXElementpresent == 0) { DispManXElementpresent = 1; dispmanxupdate = vc_dispmanx_update_start( 10 ); dispmanxelement = vc_dispmanx_element_add( dispmanxupdate, dispmanxdisplay, 2000, // layer &dst_rect, dispmanxresource_amigafb_1, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, // clamp DISPMANX_NO_ROTATE ); vc_dispmanx_update_submit(dispmanxupdate,NULL,NULL); //dispmanxupdate = vc_dispmanx_update_start( 10 ); } if(prSDLScreen != NULL) { InitAmigaVidMode(p); init_row_map(); } //framecnt = 1; // Don't draw frame before reset done }
int main(int argc, char *argv[]) { int ret; VC_RECT_T src_rect; VC_RECT_T dst_rect; DISPMANX_UPDATE_HANDLE_T update; uint32_t vc_image_ptr; bcm_host_init(); display = vc_dispmanx_display_open( 0 ); image = calloc( 1, PITCH * HEIGHT ); // buffer 0 assert(image); // initialize image buffer with clock run in int n, m, clock = 0x275555; for (m=0; m<24; m++) { for (n=0; n<HEIGHT; n++) { ROW(n)[m] = clock&1; } clock = clock >> 1; } // fill up image with filler packets // get_packet will return filler because we haven't loaded the fifo yet. get_packet(ROW(0)+24); for (n=1; n<HEIGHT; n++) { memcpy(ROW(n)+24, ROW(0)+24, 336); } // set up some resources vc_dispmanx_rect_set( &image_rect, 0, 0, WIDTH, HEIGHT); for (n=0;n<3;n++) { resource[n] = vc_dispmanx_resource_create( TYPE, WIDTH, HEIGHT, &vc_image_ptr ); assert( resource[n] ); ret = vc_dispmanx_resource_set_palette( resource[n], palette, 0, sizeof palette ); assert( ret == 0 ); ret = vc_dispmanx_resource_write_data( resource[n], TYPE, PITCH, image, &image_rect ); assert( ret == 0 ); } vc_dispmanx_rect_set( &image_rect, OFFSET+24, 0, 336, HEIGHT); // from now on, only copy the parts that change update = vc_dispmanx_update_start( 10 ); assert( update ); vc_dispmanx_rect_set( &src_rect, 0, 0, WIDTH << 16, HEIGHT << 16 ); vc_dispmanx_rect_set( &dst_rect, 0, 0, 720, HEIGHT ); element = vc_dispmanx_element_add( update, display, 2000, &dst_rect, resource[2], &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, VC_IMAGE_ROT0 ); ret = vc_dispmanx_update_submit_sync( update ); assert( ret == 0 ); // BUG: clear any existing callbacks, even to other apps. // https://github.com/raspberrypi/userland/issues/218 vc_dispmanx_vsync_callback(display, NULL, NULL); vc_dispmanx_vsync_callback(display, vsync, NULL); if (argc == 2 && argv[1][0] == '-') { while(read_packets()) { ; } } else { demo(); } vc_dispmanx_vsync_callback(display, NULL, NULL); // disable callback update = vc_dispmanx_update_start( 10 ); assert( update ); ret = vc_dispmanx_element_remove( update, element ); assert( ret == 0 ); ret = vc_dispmanx_update_submit_sync( update ); assert( ret == 0 ); for (n=0; n<3; n++) { ret = vc_dispmanx_resource_delete( resource[0] ); assert( ret == 0 ); } ret = vc_dispmanx_display_close( display ); assert( ret == 0 ); return 0; }
void newLife( LIFE_T *life, int32_t size) { life->width = size; life->height = size; life->alignedWidth = ALIGN_TO_16(life->width); life->alignedHeight = ALIGN_TO_16(life->height); life->pitch = ALIGN_TO_16(life->width); life->buffer = calloc(1, life->pitch * life->alignedHeight); if (life->buffer == NULL) { fprintf(stderr, "life: memory exhausted\n"); exit(EXIT_FAILURE); } life->fieldLength = life->width * life->height; life->field = calloc(1, life->fieldLength); if (life->field == NULL) { fprintf(stderr, "life: memory exhausted\n"); exit(EXIT_FAILURE); } life->fieldNext = calloc(1, life->fieldLength); if (life->fieldNext == NULL) { fprintf(stderr, "life: memory exhausted\n"); exit(EXIT_FAILURE); } struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_usec); int32_t row = 0; for (row = 0 ; row < life->height ; row++) { int32_t col = 0; for (col = 0 ; col < life->width ; col++) { if (rand() > (RAND_MAX / 2)) { setCell(life, col, row); } else { life->buffer[col + (row * life->alignedWidth)] = DEAD; } } } //--------------------------------------------------------------------- VC_IMAGE_TYPE_T type = VC_IMAGE_8BPP; uint32_t vc_image_ptr; int result = 0; life->frontResource = vc_dispmanx_resource_create( type, life->width | (life->pitch << 16), life->height | (life->alignedHeight << 16), &vc_image_ptr); assert(life->frontResource != 0); life->backResource = vc_dispmanx_resource_create( type, life->width | (life->pitch << 16), life->height | (life->alignedHeight << 16), &vc_image_ptr); assert(life->backResource != 0); //--------------------------------------------------------------------- vc_dispmanx_rect_set(&(life->bmpRect), 0, 0, life->width, life->height); result = vc_dispmanx_resource_write_data(life->frontResource, type, life->pitch, life->buffer, &(life->bmpRect)); assert(result == 0); //--------------------------------------------------------------------- long cores = sysconf(_SC_NPROCESSORS_ONLN); if (cores == -1) { cores = 1; } if (cores > LIFE_MAX_THREADS) { life->numberOfThreads = LIFE_MAX_THREADS; } else { life->numberOfThreads = cores; } pthread_barrier_init(&(life->startIterationBarrier), NULL, life->numberOfThreads + 1); pthread_barrier_init(&(life->finishedIterationBarrier), NULL, life->numberOfThreads + 1); //--------------------------------------------------------------------- int32_t heightStep = life->height / life->numberOfThreads; int32_t heightStart = 0; int32_t thread; for (thread = 0 ; thread < life->numberOfThreads ; thread++) { life->heightRange[thread].startHeight = heightStart; life->heightRange[thread].endHeight = heightStart + heightStep; heightStart += heightStep; pthread_create(&(life->threads[thread]), NULL, workerLife, life); } thread = life->numberOfThreads - 1; life->heightRange[thread].endHeight = life->height; //--------------------------------------------------------------------- memcpy(life->field, life->fieldNext, life->fieldLength); pthread_barrier_wait(&(life->startIterationBarrier)); }
static void *display_thread (void *unused) { VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 255 /*alpha 0->255*/ , 0 }; uint32_t vc_image_ptr; SDL_Surface *Dummy_prSDLScreen; int width, height; bool callback_registered = false; for(;;) { display_thread_busy = false; uae_u32 signal = read_comm_pipe_u32_blocking(display_pipe); display_thread_busy = true; switch(signal) { case DISPLAY_SIGNAL_SETUP: if(!callback_registered) { bcm_host_init(); dispmanxdisplay = vc_dispmanx_display_open(0); vc_dispmanx_vsync_callback(dispmanxdisplay, vsync_callback, NULL); callback_registered = true; } break; case DISPLAY_SIGNAL_SUBSHUTDOWN: if (DispManXElementpresent == 1) { DispManXElementpresent = 0; dispmanxupdate = vc_dispmanx_update_start(0); vc_dispmanx_element_remove(dispmanxupdate, dispmanxelement); vc_dispmanx_update_submit_sync(dispmanxupdate); } if (dispmanxresource_amigafb_1 != 0) { vc_dispmanx_resource_delete(dispmanxresource_amigafb_1); dispmanxresource_amigafb_1 = 0; } if (dispmanxresource_amigafb_2 != 0) { vc_dispmanx_resource_delete(dispmanxresource_amigafb_2); dispmanxresource_amigafb_2 = 0; } if(prSDLScreen != NULL) { SDL_FreeSurface(prSDLScreen); prSDLScreen = NULL; } uae_sem_post (&display_sem); break; case DISPLAY_SIGNAL_OPEN: width = display_width; height = display_height; Dummy_prSDLScreen = SDL_SetVideoMode(width, height, 16, SDL_SWSURFACE | SDL_FULLSCREEN); prSDLScreen = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height, 16, Dummy_prSDLScreen->format->Rmask, Dummy_prSDLScreen->format->Gmask, Dummy_prSDLScreen->format->Bmask, Dummy_prSDLScreen->format->Amask); SDL_FreeSurface(Dummy_prSDLScreen); vc_dispmanx_display_get_info(dispmanxdisplay, &dispmanxdinfo); dispmanxresource_amigafb_1 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr); dispmanxresource_amigafb_2 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr); vc_dispmanx_rect_set(&blit_rect, 0, 0, width, height); vc_dispmanx_resource_write_data(dispmanxresource_amigafb_1, VC_IMAGE_RGB565, prSDLScreen->pitch, prSDLScreen->pixels, &blit_rect); vc_dispmanx_rect_set(&src_rect, 0, 0, width << 16, height << 16); // 16/9 to 4/3 ratio adaptation. if (currprefs.gfx_correct_aspect == 0 || screen_is_picasso) { // Fullscreen. int scaled_width = dispmanxdinfo.width * currprefs.gfx_fullscreen_ratio / 100; int scaled_height = dispmanxdinfo.height * currprefs.gfx_fullscreen_ratio / 100; vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width - scaled_width)/2, (dispmanxdinfo.height - scaled_height)/2, scaled_width, scaled_height); } else { // 4/3 shrink. int scaled_width = dispmanxdinfo.width * currprefs.gfx_fullscreen_ratio / 100; int scaled_height = dispmanxdinfo.height * currprefs.gfx_fullscreen_ratio / 100; vc_dispmanx_rect_set( &dst_rect, (dispmanxdinfo.width - scaled_width / 16 * 12)/2, (dispmanxdinfo.height - scaled_height)/2, scaled_width/16*12, scaled_height); } if (DispManXElementpresent == 0) { DispManXElementpresent = 1; dispmanxupdate = vc_dispmanx_update_start(0); dispmanxelement = vc_dispmanx_element_add(dispmanxupdate, dispmanxdisplay, 2, // layer &dst_rect, dispmanxresource_amigafb_1, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, DISPMANX_NO_ROTATE); vc_dispmanx_update_submit(dispmanxupdate, NULL, NULL); } uae_sem_post (&display_sem); break; case DISPLAY_SIGNAL_SHOW: if (current_resource_amigafb == 1) { current_resource_amigafb = 0; vc_dispmanx_resource_write_data(dispmanxresource_amigafb_1, VC_IMAGE_RGB565, adisplays.gfxvidinfo.drawbuffer.rowbytes, adisplays.gfxvidinfo.drawbuffer.bufmem, &blit_rect); dispmanxupdate = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(dispmanxupdate, dispmanxelement, dispmanxresource_amigafb_1); } else { current_resource_amigafb = 1; vc_dispmanx_resource_write_data(dispmanxresource_amigafb_2, VC_IMAGE_RGB565, adisplays.gfxvidinfo.drawbuffer.rowbytes, adisplays.gfxvidinfo.drawbuffer.bufmem, &blit_rect); dispmanxupdate = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(dispmanxupdate, dispmanxelement, dispmanxresource_amigafb_2); } vc_dispmanx_update_submit(dispmanxupdate, NULL, NULL); break; case DISPLAY_SIGNAL_QUIT: callback_registered = false; vc_dispmanx_vsync_callback(dispmanxdisplay, NULL, NULL); vc_dispmanx_display_close(dispmanxdisplay); bcm_host_deinit(); SDL_VideoQuit(); display_tid = 0; return 0; } } }
static jlong fbDispmanCreateNativeCursor(JNIEnv *env, jint x, jint y, jbyte *srcArray, jint width, jint height) { VC_RECT_T pixelRect; int rc; uint32_t imagePtr; jbyte *allocatedBuffer = NULL; DispmanCursorImage *cursorImage = (DispmanCursorImage *)malloc(sizeof(DispmanCursorImage)); //Width should be aligned to 16 pixels if (width % 16 != 0) { int newWidth = width + 16 - (width % 16); allocatedBuffer = (jbyte *)malloc(newWidth * height * 4); int i; int offset = 0; for (i = 0; i < height; ++i) { memcpy(allocatedBuffer + offset, srcArray, width * 4); memset(allocatedBuffer + offset + (width * 4), 0, (newWidth - width) * 4); offset += newWidth * 4; srcArray += width * 4; } width = newWidth; srcArray = allocatedBuffer; } pixelRect.x = 0; pixelRect.y = 0; pixelRect.width = width; pixelRect.height = height; cursorImage->x = x; cursorImage->y = y; cursorImage->width = width; cursorImage->height = height; cursorImage->resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, width, height, &imagePtr); if (cursorImage->resource == 0) { GLASS_LOG_SEVERE("Cannot create resource"); if (allocatedBuffer != NULL) { free(allocatedBuffer); allocatedBuffer = NULL; } free(cursorImage); return 0; } rc = vc_dispmanx_resource_write_data(cursorImage->resource, VC_IMAGE_ARGB8888, width * 4, srcArray, &pixelRect); if (allocatedBuffer != NULL) { free(allocatedBuffer); allocatedBuffer = NULL; } if (rc != 0) { GLASS_LOG_SEVERE("Cannot write pixels"); free(cursorImage); return 0; } return ptr_to_jlong(cursorImage); }