/** * Resize the texture * * This will automatically create the texture if it does not exist * * @note requires to be called within the obs graphics context */ static inline void xshm_resize_texture(struct xshm_data *data) { if (data->texture) gs_texture_destroy(data->texture); data->texture = gs_texture_create(data->width, data->height, GS_BGRA, 1, NULL, GS_DYNAMIC); }
static bool texrender_resetbuffer(gs_texrender_t texrender, uint32_t cx, uint32_t cy) { if (!texrender) return false; gs_texture_destroy(texrender->target); gs_zstencil_destroy(texrender->zs); texrender->target = NULL; texrender->zs = NULL; texrender->cx = cx; texrender->cy = cy; texrender->target = gs_texture_create(cx, cy, texrender->format, 1, NULL, GS_RENDER_TARGET); if (!texrender->target) return false; if (texrender->zsformat != GS_ZS_NONE) { texrender->zs = gs_zstencil_create(cx, cy, texrender->zsformat); if (!texrender->zs) { gs_texture_destroy(texrender->target); texrender->target = NULL; return false; } } return true; }
void gs_image_file_init_texture(gs_image_file_t *image) { if (!image->loaded) return; if (image->is_animated_gif) { image->texture = gs_texture_create( image->cx, image->cy, image->format, 1, (const uint8_t**)&image->gif.frame_image, GS_DYNAMIC); } else { image->texture = gs_texture_create( image->cx, image->cy, image->format, 1, (const uint8_t**)&image->texture_data, 0); bfree(image->texture_data); image->texture_data = NULL; } }
/** * Resize the texture * * This will automatically create the texture if it does not exist */ static void xshm_resize_texture(struct xshm_data *data) { obs_enter_graphics(); if (data->texture) gs_texture_destroy(data->texture); data->texture = gs_texture_create(data->width, data->height, GS_BGRA, 1, NULL, GS_DYNAMIC); obs_leave_graphics(); }
void set_deinterlace_texture_size(obs_source_t *source) { if (source->async_gpu_conversion) { source->async_prev_texrender = gs_texrender_create(GS_BGRX, GS_ZS_NONE); source->async_prev_texture = gs_texture_create( source->async_convert_width, source->async_convert_height, source->async_texture_format, 1, NULL, GS_DYNAMIC); } else { enum gs_color_format format = convert_video_format( source->async_format); source->async_prev_texture = gs_texture_create( source->async_width, source->async_height, format, 1, NULL, GS_DYNAMIC); } }
static bool obs_init_textures(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; bool yuv = format_is_yuv(ovi->output_format); uint32_t output_height = video->gpu_conversion ? video->conversion_height : ovi->output_height; size_t i; for (i = 0; i < NUM_TEXTURES; i++) { video->copy_surfaces[i] = gs_stagesurface_create( ovi->output_width, output_height, GS_RGBA); if (!video->copy_surfaces[i]) return false; video->render_textures[i] = gs_texture_create( ovi->base_width, ovi->base_height, GS_RGBA, 1, NULL, GS_RENDER_TARGET); if (!video->render_textures[i]) return false; video->output_textures[i] = gs_texture_create( ovi->output_width, ovi->output_height, GS_RGBA, 1, NULL, GS_RENDER_TARGET); if (!video->output_textures[i]) return false; if (yuv) obs_source_frame_init(&video->convert_frames[i], ovi->output_format, ovi->output_width,ovi->output_height); } return true; }
bool BrowserSource::Impl::Listener::CreatePopupSurface(int width, int height, int x, int y, BrowserSurfaceHandle *popupSurfaceHandle) { obs_enter_graphics(); gs_texture_t *newTexture = gs_texture_create(width, height, GS_BGRA, 1, nullptr, GS_DYNAMIC); obs_leave_graphics(); *popupSurfaceHandle = newTexture; popupSurface = newTexture; popupX = x; popupY = y; return true; }
static inline void init_textures(struct dc_capture *capture) { if (capture->compatibility) capture->texture = gs_texture_create( capture->width, capture->height, GS_BGRA, 1, NULL, GS_DYNAMIC); else capture->texture = gs_texture_create_gdi( capture->width, capture->height); if (!capture->texture) { blog(LOG_WARNING, "[dc_capture_init] Failed to " "create textures"); return; } capture->valid = true; }
bool BrowserSource::Impl::Listener::CreateSurface(int width, int height, BrowserSurfaceHandle *surfaceHandle) { //TODO: We can't lock graphics on CEF thread // as there may be a synchronous call obs_enter_graphics(); gs_texture_t *newTexture = gs_texture_create(width, height, GS_BGRA, 1, nullptr, GS_DYNAMIC); obs_leave_graphics(); textureSet.insert(newTexture); *surfaceHandle = newTexture; return true; }
gs_texture_t *gs_texture_create_from_file(const char *file) { struct ffmpeg_image image; gs_texture_t *tex = NULL; if (ffmpeg_image_init(&image, file)) { uint8_t *data = malloc(image.cx * image.cy * 4); if (ffmpeg_image_decode(&image, data, image.cx * 4)) { tex = gs_texture_create(image.cx, image.cy, convert_format(image.format), 1, (const uint8_t**)&data, 0); } ffmpeg_image_free(&image); free(data); } return tex; }
static inline void copy_texture(gs_duplicator_t *d, ID3D11Texture2D *tex) { D3D11_TEXTURE2D_DESC desc; tex->GetDesc(&desc); if (!d->texture || d->texture->width != desc.Width || d->texture->height != desc.Height) { delete d->texture; d->texture = (gs_texture_2d*)gs_texture_create( desc.Width, desc.Height, ConvertDXGITextureFormat(desc.Format), 1, nullptr, 0); } if (!!d->texture) d->device->context->CopyResource(d->texture->texture, tex); }
/* * Create the cursor texture, either by updating if the new cursor has the same * size or by creating a new texture if the size is different */ static void xcursor_create(xcursor_t *data, XFixesCursorImage *xc) { uint32_t *pixels = xcursor_pixels(xc); if (data->tex && data->last_height == xc->width && data->last_width == xc->height) { gs_texture_set_image(data->tex, (const uint8_t *) pixels, xc->width * sizeof(uint32_t), False); } else { if (data->tex) gs_texture_destroy(data->tex); data->tex = gs_texture_create(xc->width, xc->height, GS_BGRA, 1, (const uint8_t **) &pixels, GS_DYNAMIC); } bfree(pixels); data->last_serial = xc->cursor_serial; data->last_width = xc->width; data->last_height = xc->height; }
/* * Create the cursor texture, either by updating if the new cursor has the same * size or by creating a new texture if the size is different */ static void xcb_xcursor_create(xcb_xcursor_t *data, xcb_xfixes_get_cursor_image_reply_t *xc) { uint32_t *pixels = xcb_xfixes_get_cursor_image_cursor_image(xc); if (!pixels) return; if (data->tex && data->last_height == xc->width && data->last_width == xc->height) { gs_texture_set_image(data->tex, (const uint8_t *) pixels, xc->width * sizeof(uint32_t), false); } else { if (data->tex) gs_texture_destroy(data->tex); data->tex = gs_texture_create(xc->width, xc->height, GS_BGRA, 1, (const uint8_t **) &pixels, GS_DYNAMIC); } data->last_serial = xc->cursor_serial; data->last_width = xc->width; data->last_height = xc->height; }
static bool obs_init_gpu_conversion(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; calc_gpu_conversion_sizes(ovi); if (!video->conversion_height) { blog(LOG_INFO, "GPU conversion not available for format: %u", (unsigned int)ovi->output_format); video->gpu_conversion = false; return true; } for (size_t i = 0; i < NUM_TEXTURES; i++) { video->convert_textures[i] = gs_texture_create( ovi->output_width, video->conversion_height, GS_RGBA, 1, NULL, GS_RENDER_TARGET); if (!video->convert_textures[i]) return false; } return true; }
void XCompcapMain::updateSettings(obs_data_t *settings) { PLock lock(&p->lock); XErrorLock xlock; ObsGsContextHolder obsctx; blog(LOG_DEBUG, "Settings updating"); Window prevWin = p->win; xcc_cleanup(p); if (settings) { const char *windowName = obs_data_get_string(settings, "capture_window"); p->windowName = windowName; p->win = getWindowFromString(windowName); p->cut_top = obs_data_get_int(settings, "cut_top"); p->cut_left = obs_data_get_int(settings, "cut_left"); p->cut_right = obs_data_get_int(settings, "cut_right"); p->cut_bot = obs_data_get_int(settings, "cut_bot"); p->lockX = obs_data_get_bool(settings, "lock_x"); p->swapRedBlue = obs_data_get_bool(settings, "swap_redblue"); p->show_cursor = obs_data_get_bool(settings, "show_cursor"); p->include_border = obs_data_get_bool(settings, "include_border"); p->exclude_alpha = obs_data_get_bool(settings, "exclude_alpha"); } else { p->win = prevWin; } xlock.resetError(); if (p->win) XCompositeRedirectWindow(xdisp, p->win, CompositeRedirectAutomatic); if (xlock.gotError()) { blog(LOG_ERROR, "XCompositeRedirectWindow failed: %s", xlock.getErrorText().c_str()); return; } if (p->win) XSelectInput(xdisp, p->win, StructureNotifyMask | ExposureMask); XSync(xdisp, 0); XWindowAttributes attr; if (!p->win || !XGetWindowAttributes(xdisp, p->win, &attr)) { p->win = 0; p->width = 0; p->height = 0; return; } if (p->win && p->cursor && p->show_cursor) { Window child; int x, y; XTranslateCoordinates(xdisp, p->win, attr.root, 0, 0, &x, &y, &child); xcursor_offset(p->cursor, x, y); } gs_color_format cf = GS_RGBA; if (p->exclude_alpha) { cf = GS_BGRX; } p->border = attr.border_width; if (p->include_border) { p->width = attr.width + p->border * 2; p->height = attr.height + p->border * 2; } else { p->width = attr.width; p->height = attr.height; } if (p->cut_top + p->cut_bot < (int)p->height) { p->cur_cut_top = p->cut_top; p->cur_cut_bot = p->cut_bot; } else { p->cur_cut_top = 0; p->cur_cut_bot = 0; } if (p->cut_left + p->cut_right < (int)p->width) { p->cur_cut_left = p->cut_left; p->cur_cut_right = p->cut_right; } else { p->cur_cut_left = 0; p->cur_cut_right = 0; } if (p->tex) gs_texture_destroy(p->tex); uint8_t *texData = new uint8_t[width() * height() * 4]; memset(texData, 0, width() * height() * 4); const uint8_t* texDataArr[] = { texData, 0 }; p->tex = gs_texture_create(width(), height(), cf, 1, texDataArr, 0); delete[] texData; if (p->swapRedBlue) { GLuint tex = *(GLuint*)gs_texture_get_obj(p->tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); glBindTexture(GL_TEXTURE_2D, 0); } const int attrs[] = { GLX_BIND_TO_TEXTURE_RGBA_EXT, GL_TRUE, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, GLX_DOUBLEBUFFER, GL_FALSE, None }; int nelem = 0; GLXFBConfig* configs = glXChooseFBConfig(xdisp, XCompcap::getRootWindowScreen(attr.root), attrs, &nelem); if (nelem <= 0) { blog(LOG_ERROR, "no matching fb config found"); p->win = 0; p->height = 0; p->width = 0; return; } glXGetFBConfigAttrib(xdisp, configs[0], GLX_Y_INVERTED_EXT, &nelem); p->inverted = nelem != 0; xlock.resetError(); p->pixmap = XCompositeNameWindowPixmap(xdisp, p->win); if (xlock.gotError()) { blog(LOG_ERROR, "XCompositeNameWindowPixmap failed: %s", xlock.getErrorText().c_str()); p->pixmap = 0; XFree(configs); return; } const int attribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, None }; p->glxpixmap = glXCreatePixmap(xdisp, configs[0], p->pixmap, attribs); if (xlock.gotError()) { blog(LOG_ERROR, "glXCreatePixmap failed: %s", xlock.getErrorText().c_str()); XFreePixmap(xdisp, p->pixmap); XFree(configs); p->pixmap = 0; p->glxpixmap = 0; return; } XFree(configs); p->gltex = gs_texture_create(p->width, p->height, cf, 1, 0, GS_GL_DUMMYTEX); GLuint gltex = *(GLuint*)gs_texture_get_obj(p->gltex); glBindTexture(GL_TEXTURE_2D, gltex); glXBindTexImageEXT(xdisp, p->glxpixmap, GLX_FRONT_LEFT_EXT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }
void cache_glyphs(struct ft2_source *srcdata, wchar_t *cache_glyphs) { FT_GlyphSlot slot; FT_UInt glyph_index = 0; if (!srcdata->font_face) return; slot = srcdata->font_face->glyph; uint32_t dx = srcdata->texbuf_x, dy = srcdata->texbuf_y; uint8_t alpha; int32_t cached_glyphs = 0; for (uint32_t i = 0; i < wcslen(cache_glyphs); i++) { glyph_index = FT_Get_Char_Index(srcdata->font_face, cache_glyphs[i]); if (src_glyph != NULL) goto skip_glyph; FT_Load_Glyph(srcdata->font_face, glyph_index, FT_LOAD_DEFAULT); FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); uint32_t g_w = slot->bitmap.width; uint32_t g_h = slot->bitmap.rows; if (srcdata->max_h < g_h) srcdata->max_h = g_h; if (dx + g_w >= texbuf_w) { dx = 0; dy += srcdata->max_h + 1; } src_glyph = bzalloc(sizeof(struct glyph_info)); src_glyph->u = (float)dx / (float)texbuf_w; src_glyph->u2 = (float)(dx + g_w) / (float)texbuf_w; src_glyph->v = (float)dy / (float)texbuf_h; src_glyph->v2 = (float)(dy + g_h) / (float)texbuf_h; src_glyph->w = g_w; src_glyph->h = g_h; src_glyph->yoff = slot->bitmap_top; src_glyph->xoff = slot->bitmap_left; src_glyph->xadv = slot->advance.x >> 6; for (uint32_t y = 0; y < g_h; y++) { for (uint32_t x = 0; x < g_w; x++) { alpha = slot->bitmap.buffer[glyph_pos]; srcdata->texbuf[buf_pos] = 0x00FFFFFF ^ (alpha << 24); } } dx += (g_w + 1); if (dx >= texbuf_w) { dx = 0; dy += srcdata->max_h; } cached_glyphs++; skip_glyph:; } srcdata->texbuf_x = dx; srcdata->texbuf_y = dy; if (cached_glyphs > 0) { obs_enter_graphics(); if (srcdata->tex != NULL) { gs_texture_t tmp_texture = NULL; tmp_texture = srcdata->tex; srcdata->tex = NULL; gs_texture_destroy(tmp_texture); } srcdata->tex = gs_texture_create(texbuf_w, texbuf_h, GS_RGBA, 1, (const uint8_t **)&srcdata->texbuf, 0); obs_leave_graphics(); } }
void cache_glyphs(struct ft2_source *srcdata, wchar_t *cache_glyphs) { FT_GlyphSlot slot = 0; FT_UInt glyph_index = 0; if (!srcdata->font_face || !cache_glyphs) return; //slot = srcdata->font_face->glyph; uint32_t dx = srcdata->texbuf_x, dy = srcdata->texbuf_y; uint8_t alpha; int32_t cached_glyphs = 0; size_t len = wcslen(cache_glyphs); for (size_t i = 0; i < len; i++) { FT_Face curFace; glyph_index = FT_Get_Char_Index_Fallback(srcdata, &curFace, cache_glyphs[i]); if (curFace == 0) goto skip_glyph; slot = curFace->glyph; if (src_glyph != NULL) goto skip_glyph; FT_Load_Glyph(curFace, glyph_index, FT_LOAD_DEFAULT); bool isUseFallback = slot->face == srcdata->fallback_face; bool shouldBolden = ((!isUseFallback && srcdata->fake_bold) || (isUseFallback && srcdata->fallback_fake_bold)); if (slot->format == FT_GLYPH_FORMAT_OUTLINE && shouldBolden) FT_Outline_EmboldenXY(&slot->outline, 0x80, 0x40); FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); uint32_t g_w = slot->bitmap.width; uint32_t g_h = slot->bitmap.rows; if (srcdata->max_h < g_h) srcdata->max_h = g_h; if (dx + g_w >= texbuf_w) { dx = 0; dy += srcdata->max_h + 1; } src_glyph = bzalloc(sizeof(struct glyph_info)); src_glyph->u = (float)dx / (float)texbuf_w; src_glyph->u2 = (float)(dx + g_w) / (float)texbuf_w; src_glyph->v = (float)dy / (float)texbuf_h; src_glyph->v2 = (float)(dy + g_h) / (float)texbuf_h; src_glyph->w = g_w; src_glyph->h = g_h; src_glyph->yoff = slot->bitmap_top; src_glyph->xoff = slot->bitmap_left; src_glyph->xadv = slot->advance.x >> 6; for (uint32_t y = 0; y < g_h; y++) { for (uint32_t x = 0; x < g_w; x++) { alpha = slot->bitmap.buffer[glyph_pos]; srcdata->texbuf[buf_pos] = 0x00FFFFFF ^ ((uint32_t)alpha << 24); } } dx += (g_w + 1); if (dx >= texbuf_w) { dx = 0; dy += srcdata->max_h; } cached_glyphs++; skip_glyph:; } srcdata->texbuf_x = dx; srcdata->texbuf_y = dy; if (cached_glyphs > 0) { obs_enter_graphics(); if (srcdata->tex != NULL) { gs_texture_t *tmp_texture = NULL; tmp_texture = srcdata->tex; srcdata->tex = NULL; gs_texture_destroy(tmp_texture); } srcdata->tex = gs_texture_create(texbuf_w, texbuf_h, GS_RGBA, 1, (const uint8_t **)&srcdata->texbuf, 0); obs_leave_graphics(); } }