static int X11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { X11_RenderData *renderdata = (X11_RenderData *) renderer->driverdata; SDL_Window *window = renderer->window; SDL_VideoDisplay *display = window->display; X11_TextureData *data; int pitch_alignmask = ((renderdata->scanline_pad / 8) - 1); data = (X11_TextureData *) SDL_calloc(1, sizeof(*data)); if (!data) { SDL_OutOfMemory(); return -1; } texture->driverdata = data; if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { data->yuv = SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h); if (!data->yuv) { return -1; } data->format = display->current_mode.format; } else { /* The image/pixmap depth must be the same as the window or you get a BadMatch error when trying to putimage or copyarea. */ if (texture->format != display->current_mode.format) { SDL_SetError("Texture format doesn't match window format"); return -1; } data->format = texture->format; } data->pitch = texture->w * SDL_BYTESPERPIXEL(data->format); data->pitch = (data->pitch + pitch_alignmask) & ~pitch_alignmask; if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING) { #ifndef NO_SHARED_MEMORY XShmSegmentInfo *shminfo = &data->shminfo; shm_error = True; if (SDL_X11_HAVE_SHM) { shminfo->shmid = shmget(IPC_PRIVATE, texture->h * data->pitch, IPC_CREAT | 0777); if (shminfo->shmid >= 0) { shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0); shminfo->readOnly = False; if (shminfo->shmaddr != (char *) -1) { shm_error = False; X_handler = XSetErrorHandler(shm_errhandler); XShmAttach(renderdata->display, shminfo); XSync(renderdata->display, False); XSetErrorHandler(X_handler); if (shm_error) { shmdt(shminfo->shmaddr); } } shmctl(shminfo->shmid, IPC_RMID, NULL); } } if (!shm_error) { data->pixels = shminfo->shmaddr; data->image = XShmCreateImage(renderdata->display, renderdata->visual, renderdata->depth, ZPixmap, shminfo->shmaddr, shminfo, texture->w, texture->h); if (!data->image) { XShmDetach(renderdata->display, shminfo); XSync(renderdata->display, False); shmdt(shminfo->shmaddr); shm_error = True; } } if (shm_error) { shminfo->shmaddr = NULL; } if (!data->image) #endif /* not NO_SHARED_MEMORY */ { data->pixels = SDL_malloc(texture->h * data->pitch); if (!data->pixels) { X11_DestroyTexture(renderer, texture); SDL_OutOfMemory(); return -1; } data->image = XCreateImage(renderdata->display, renderdata->visual, renderdata->depth, ZPixmap, 0, data->pixels, texture->w, texture->h, SDL_BYTESPERPIXEL(data->format) * 8, data->pitch); if (!data->image) { X11_DestroyTexture(renderer, texture); SDL_SetError("XCreateImage() failed"); return -1; } } } else { data->pixmap = XCreatePixmap(renderdata->display, renderdata->xwindow, texture->w, texture->h, renderdata->depth); if (data->pixmap == None) { X11_DestroyTexture(renderer, texture); SDL_SetError("XCreatePixmap() failed"); return -1; } data->image = XCreateImage(renderdata->display, renderdata->visual, renderdata->depth, ZPixmap, 0, NULL, texture->w, texture->h, SDL_BYTESPERPIXEL(data->format) * 8, data->pitch); if (!data->image) { X11_DestroyTexture(renderer, texture); SDL_SetError("XCreateImage() failed"); return -1; } } return 0; }
/* * Copy a block of pixels of one format to another format */ int SDL_ConvertPixels(int width, int height, Uint32 src_format, const void * src, int src_pitch, Uint32 dst_format, void * dst, int dst_pitch) { SDL_Surface src_surface, dst_surface; SDL_PixelFormat src_fmt, dst_fmt; SDL_BlitMap src_blitmap, dst_blitmap; SDL_Rect rect; void *nonconst_src = (void *) src; /* Check to make sure we are blitting somewhere, so we don't crash */ if (!dst) { return SDL_InvalidParamError("dst"); } if (!dst_pitch) { return SDL_InvalidParamError("dst_pitch"); } /* Fast path for same format copy */ if (src_format == dst_format) { int bpp, i; if (SDL_ISPIXELFORMAT_FOURCC(src_format)) { switch (src_format) { case SDL_PIXELFORMAT_YUY2: case SDL_PIXELFORMAT_UYVY: case SDL_PIXELFORMAT_YVYU: bpp = 2; break; case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_NV12: case SDL_PIXELFORMAT_NV21: bpp = 1; break; default: return SDL_SetError("Unknown FOURCC pixel format"); } } else { bpp = SDL_BYTESPERPIXEL(src_format); } width *= bpp; for (i = height; i--;) { SDL_memcpy(dst, src, width); src = (Uint8*)src + src_pitch; dst = (Uint8*)dst + dst_pitch; } if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) { /* U and V planes are a quarter the size of the Y plane */ width /= 2; height /= 2; src_pitch /= 2; dst_pitch /= 2; for (i = height * 2; i--;) { SDL_memcpy(dst, src, width); src = (Uint8*)src + src_pitch; dst = (Uint8*)dst + dst_pitch; } } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) { /* U/V plane is half the height of the Y plane */ height /= 2; for (i = height; i--;) { SDL_memcpy(dst, src, width); src = (Uint8*)src + src_pitch; dst = (Uint8*)dst + dst_pitch; } } return 0; } if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src, src_pitch, &src_surface, &src_fmt, &src_blitmap)) { return -1; } if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch, &dst_surface, &dst_fmt, &dst_blitmap)) { return -1; } /* Set up the rect and go! */ rect.x = 0; rect.y = 0; rect.w = width; rect.h = height; return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect); }
static int DirectFB_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { SDL_Window *window = renderer->window; SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); SDL_DFB_DEVICEDATA(display->device); DirectFB_TextureData *data; DFBSurfaceDescription dsc; DFBSurfacePixelFormat pixelformat; DirectFB_ActivateRenderer(renderer); SDL_DFB_ALLOC_CLEAR(data, sizeof(*data)); texture->driverdata = data; /* find the right pixelformat */ pixelformat = DirectFB_SDLToDFBPixelFormat(texture->format); if (pixelformat == DSPF_UNKNOWN) { SDL_SetError("Unknown pixel format %d\n", data->format); goto error; } data->format = texture->format; data->pitch = texture->w * DFB_BYTES_PER_PIXEL(pixelformat); if (DirectFB_AcquireVidLayer(renderer, texture) != 0) { /* fill surface description */ dsc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS; dsc.width = texture->w; dsc.height = texture->h; if(texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) { /* dfb has problems with odd sizes -make them even internally */ dsc.width += (dsc.width % 2); dsc.height += (dsc.height % 2); } /* <1.2 Never use DSCAPS_VIDEOONLY here. It kills performance * No DSCAPS_SYSTEMONLY either - let dfb decide * 1.2: DSCAPS_SYSTEMONLY boosts performance by factor ~8 * Depends on other settings as well. Let dfb decide. */ dsc.caps = DSCAPS_PREMULTIPLIED; #if 0 if (texture->access == SDL_TEXTUREACCESS_STREAMING) dsc.caps |= DSCAPS_SYSTEMONLY; else dsc.caps |= DSCAPS_VIDEOONLY; #endif dsc.pixelformat = pixelformat; data->pixels = NULL; /* Create the surface */ SDL_DFB_CHECKERR(devdata->dfb->CreateSurface(devdata->dfb, &dsc, &data->surface)); if (SDL_ISPIXELFORMAT_INDEXED(data->format) && !SDL_ISPIXELFORMAT_FOURCC(data->format)) { #if 1 SDL_DFB_CHECKERR(data->surface->GetPalette(data->surface, &data->palette)); #else /* DFB has issues with blitting LUT8 surfaces. * Creating a new palette does not help. */ DFBPaletteDescription pal_desc; pal_desc.flags = DPDESC_SIZE; // | DPDESC_ENTRIES pal_desc.size = 256; SDL_DFB_CHECKERR(devdata->dfb->CreatePalette(devdata->dfb, &pal_desc,&data->palette)); SDL_DFB_CHECKERR(data->surface->SetPalette(data->surface, data->palette)); #endif } } #if (DFB_VERSION_ATLEAST(1,2,0)) data->render_options = DSRO_NONE; #endif if (texture->access == SDL_TEXTUREACCESS_STREAMING) { /* 3 plane YUVs return 1 bpp, but we need more space for other planes */ if(texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) { SDL_DFB_ALLOC_CLEAR(data->pixels, (texture->h * data->pitch + ((texture->h + texture->h % 2) * (data->pitch + data->pitch % 2) * 2) / 4)); } else { SDL_DFB_ALLOC_CLEAR(data->pixels, texture->h * data->pitch); } } return 0; error: SDL_DFB_RELEASE(data->palette); SDL_DFB_RELEASE(data->surface); SDL_DFB_FREE(texture->driverdata); return -1; }
SDL_Texture * SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface) { const SDL_PixelFormat *fmt; SDL_bool needAlpha; Uint32 i; Uint32 format; SDL_Texture *texture; CHECK_RENDERER_MAGIC(renderer, NULL); if (!surface) { SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface"); return NULL; } /* See what the best texture format is */ fmt = surface->format; if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) { needAlpha = SDL_TRUE; } else { needAlpha = SDL_FALSE; } format = renderer->info.texture_formats[0]; for (i = 0; i < renderer->info.num_texture_formats; ++i) { if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) && SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) { format = renderer->info.texture_formats[i]; break; } } texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC, surface->w, surface->h); if (!texture) { return NULL; } if (format == surface->format->format) { if (SDL_MUSTLOCK(surface)) { SDL_LockSurface(surface); SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); SDL_UnlockSurface(surface); } else { SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); } } else { SDL_PixelFormat *dst_fmt; SDL_Surface *temp = NULL; /* Set up a destination surface for the texture update */ dst_fmt = SDL_AllocFormat(format); temp = SDL_ConvertSurface(surface, dst_fmt, 0); SDL_FreeFormat(dst_fmt); if (temp) { SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch); SDL_FreeSurface(temp); } else { SDL_DestroyTexture(texture); return NULL; } } { Uint8 r, g, b, a; SDL_BlendMode blendMode; SDL_GetSurfaceColorMod(surface, &r, &g, &b); SDL_SetTextureColorMod(texture, r, g, b); SDL_GetSurfaceAlphaMod(surface, &a); SDL_SetTextureAlphaMod(texture, a); if (SDL_GetColorKey(surface, NULL) == 0) { /* We converted to a texture with alpha format */ SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); } else { SDL_GetSurfaceBlendMode(surface, &blendMode); SDL_SetTextureBlendMode(texture, blendMode); } } return texture; }
SDL_Texture * SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h) { SDL_Texture *texture; CHECK_RENDERER_MAGIC(renderer, NULL); if (!format) { format = renderer->info.texture_formats[0]; } if (SDL_ISPIXELFORMAT_INDEXED(format)) { SDL_SetError("Palettized textures are not supported"); return NULL; } if (w <= 0 || h <= 0) { SDL_SetError("Texture dimensions can't be 0"); return NULL; } texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture)); if (!texture) { SDL_OutOfMemory(); return NULL; } texture->magic = &texture_magic; texture->format = format; texture->access = access; texture->w = w; texture->h = h; texture->r = 255; texture->g = 255; texture->b = 255; texture->a = 255; texture->renderer = renderer; texture->next = renderer->textures; if (renderer->textures) { renderer->textures->prev = texture; } renderer->textures = texture; if (IsSupportedFormat(renderer, format)) { if (renderer->CreateTexture(renderer, texture) < 0) { SDL_DestroyTexture(texture); return 0; } } else { texture->native = SDL_CreateTexture(renderer, GetClosestSupportedFormat(renderer, format), access, w, h); if (!texture->native) { SDL_DestroyTexture(texture); return NULL; } /* Swap textures to have texture before texture->native in the list */ texture->native->next = texture->next; if (texture->native->next) { texture->native->next->prev = texture->native; } texture->prev = texture->native->prev; if (texture->prev) { texture->prev->next = texture; } texture->native->prev = texture; texture->next = texture->native; renderer->textures = texture; if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { texture->yuv = SDL_SW_CreateYUVTexture(format, w, h); if (!texture->yuv) { SDL_DestroyTexture(texture); return NULL; } } else if (access == SDL_TEXTUREACCESS_STREAMING) { /* The pitch is 4 byte aligned */ texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3); texture->pixels = SDL_calloc(1, texture->pitch * h); if (!texture->pixels) { SDL_DestroyTexture(texture); return NULL; } } } return texture; }
static int DirectFB_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { SDL_Window *window = SDL_GetWindowFromID(renderer->window); SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); SDL_DFB_DEVICEDATA(display->device); DirectFB_TextureData *data; DFBResult ret; DFBSurfaceDescription dsc; SDL_DFB_CALLOC(data, 1, sizeof(*data)); texture->driverdata = data; data->format = texture->format; data->pitch = (texture->w * SDL_BYTESPERPIXEL(data->format)); if (DirectFB_AcquireVidLayer(renderer, texture) != 0) { /* fill surface description */ dsc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS; dsc.width = texture->w; dsc.height = texture->h; /* <1.2 Never use DSCAPS_VIDEOONLY here. It kills performance * No DSCAPS_SYSTEMONLY either - let dfb decide * 1.2: DSCAPS_SYSTEMONLY boosts performance by factor ~8 * Depends on other settings as well. Let dfb decide. */ dsc.caps = DSCAPS_PREMULTIPLIED; #if 0 if (texture->access == SDL_TEXTUREACCESS_STREAMING) dsc.caps |= DSCAPS_SYSTEMONLY; else dsc.caps |= DSCAPS_VIDEOONLY; #endif /* find the right pixelformat */ dsc.pixelformat = SDLToDFBPixelFormat(data->format); if (dsc.pixelformat == DSPF_UNKNOWN) { SDL_SetError("Unknown pixel format %d\n", data->format); goto error; } data->pixels = NULL; /* Create the surface */ SDL_DFB_CHECKERR(devdata->dfb->CreateSurface(devdata->dfb, &dsc, &data->surface)); if (SDL_ISPIXELFORMAT_INDEXED(data->format) && !SDL_ISPIXELFORMAT_FOURCC(data->format)) { SDL_DFB_CHECKERR(data->surface->GetPalette(data->surface, &data->palette)); } } #if (DFB_VERSION_ATLEAST(1,2,0)) data->render_options = DSRO_NONE; #endif if (texture->access == SDL_TEXTUREACCESS_STREAMING) { data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); SDL_DFB_CALLOC(data->pixels, 1, texture->h * data->pitch); } return 0; error: SDL_DFB_RELEASE(data->palette); SDL_DFB_RELEASE(data->surface); SDL_DFB_FREE(texture->driverdata); return -1; }