Commit 32eebfde authored by Jean-Paul Saman's avatar Jean-Paul Saman

VAAPI-X11 vout: Reworking X11 video output.

Create an X11 window with the right parent and handle its displaying, resizing and scaling of pictures.
parent 60211457
...@@ -94,12 +94,21 @@ struct vout_display_sys_t ...@@ -94,12 +94,21 @@ struct vout_display_sys_t
/* */ /* */
Window window; Window window;
Screen *screen;
Cursor blank_cursor;
Pixmap bitmap;
XColor black;
struct {
int x, y;
unsigned int depth, width, height;
} geo;
}; };
static picture_pool_t *Pool (vout_display_t *, unsigned); static picture_pool_t *Pool(vout_display_t *, unsigned);
static void Render (vout_display_t *, picture_t *, subpicture_t *); static void Render(vout_display_t *, picture_t *, subpicture_t *);
static void DisplayPicture (vout_display_t *, picture_t *, subpicture_t *); static void DisplayPicture(vout_display_t *, picture_t *, subpicture_t *);
static int Control (vout_display_t *, int, va_list); static int Control(vout_display_t *, int, va_list);
static void Manage(vout_display_t *);
/* cache management */ /* cache management */
static unsigned int cache_counter = 0; static unsigned int cache_counter = 0;
...@@ -309,56 +318,178 @@ error: ...@@ -309,56 +318,178 @@ error:
static vout_window_t *MakeWindow (vout_display_t *vd) static vout_window_t *MakeWindow (vout_display_t *vd)
{ {
vout_display_sys_t *sys = (vout_display_sys_t *)vd->sys;
vout_window_cfg_t wnd_cfg; vout_window_cfg_t wnd_cfg;
sys->conn->lock();
/* FIXME: Correct vout_window_t display size
* looks like it assumes fullscreen for
* vout_display_PlacePicture() to work as expected. */
unsigned int width, height;
int screen = DefaultScreen(sys->conn->p_x11);
width = DisplayWidth(sys->conn->p_x11, screen);
height = DisplayHeight(sys->conn->p_x11, screen);
sys->conn->unlock();
memset (&wnd_cfg, 0, sizeof (wnd_cfg)); memset (&wnd_cfg, 0, sizeof (wnd_cfg));
wnd_cfg.type = VOUT_WINDOW_TYPE_XID; wnd_cfg.type = VOUT_WINDOW_TYPE_XID;
wnd_cfg.x = var_InheritInteger (vd, "video-x"); wnd_cfg.x = var_InheritInteger (vd, "video-x");
wnd_cfg.y = var_InheritInteger (vd, "video-y"); wnd_cfg.y = var_InheritInteger (vd, "video-y");
wnd_cfg.width = width; wnd_cfg.width = vd->cfg->display.width;
wnd_cfg.height = height; wnd_cfg.height = vd->cfg->display.height;
vout_window_t *wnd = vout_display_NewWindow (vd, &wnd_cfg); vout_window_t *wnd = vout_display_NewWindow(vd, &wnd_cfg);
if (wnd == NULL) if (wnd == NULL)
msg_Err (vd, "parent window not available"); msg_Err (vd, "parent window not available");
return wnd; return wnd;
} }
static int GetWindowSize(vout_display_t *vd, unsigned int *pi_width, unsigned int *pi_height) static Screen *FindScreen(vout_display_t *vd, Display *dpy,
int *px, int *py, unsigned int *pnum, unsigned int *pdepth,
unsigned int *pwidth, unsigned int *pheight)
{ {
vout_display_sys_t *sys = vd->sys; vout_display_sys_t *sys = vd->sys;
Status status; Status status;
Window root_window; Window root_window;
unsigned int bw;
int x, y;
unsigned int bw, depth;
sys->conn->lock(); sys->conn->lock();
status = XGetGeometry(sys->conn->p_x11, status = XGetGeometry(dpy, sys->embed->handle.xid,
sys->embed->handle.xid,
&root_window, &root_window,
&x, &y, pi_width, pi_height, px, py, pwidth, pheight,
&bw, &depth); &bw, pdepth);
if (status == 0)
{
msg_Err (vd, "parent window not valid");
goto error;
}
int i = 0;
int num = 0;
Screen *screen;
Window root;
int count = XScreenCount(dpy);
for (i = 0; i < count; i++, num++)
{
screen = XScreenOfDisplay(dpy, i);
if (screen)
{
root = XRootWindowOfScreen(screen);
if (root == root_window)
{
/* found screen */
break;
}
}
}
if (i >= count)
{
msg_Err(vd, "Screen not found");
goto error;
}
/* Find the selected screen */
msg_Dbg (vd, "using screen number: %u", num);
*pnum = num;
sys->conn->unlock(); sys->conn->unlock();
return screen;
if (status == 0) error:
sys->conn->unlock();
return NULL;
}
static void WaitEvent(Display *dpy, Window w, int type)
{
XEvent e;
while (!XCheckTypedWindowEvent(dpy, w, type, &e))
usleep(10); /* FIXME: */
}
static Window CreateWindow(vout_display_t *vd, Display *dpy, Screen *screen)
{
vout_display_sys_t *sys = vd->sys;
assert(screen);
int scr = XScreenNumberOfScreen(screen);
XVisualInfo visualInfo;
XVisualInfo *vi;
vi = &visualInfo;
XMatchVisualInfo(sys->conn->p_x11, scr, sys->geo.depth, TrueColor, vi);
Colormap cmap = CopyFromParent;
XSetWindowAttributes xswa;
unsigned long xswa_mask;
xswa_mask = CWBorderPixel | CWBackPixel;
xswa.border_pixel = BlackPixel(dpy, scr);
xswa.background_pixel = BlackPixel(dpy, scr);
if (cmap != CopyFromParent)
{ {
msg_Err(vd, "failed getting geometry"); xswa_mask |= CWColormap;
return VLC_EGENERIC; xswa.colormap = cmap;
}
Window window = XCreateWindow(dpy, sys->embed->handle.xid,
sys->geo.x, sys->geo.y,
sys->geo.width, sys->geo.height,
0, sys->geo.depth,
InputOutput,
vi->visual, xswa_mask, &xswa);
if (window == None)
{
XFree(vi);
return None;
} }
return VLC_SUCCESS; if (vi != &visualInfo)
XFree(vi);
/* */
long mask = (ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
ResizeRedirectMask | StructureNotifyMask | SubstructureRedirectMask |
ExposureMask | VisibilityChangeMask);
int err = XSelectInput(dpy, window, mask);
if (err == BadWindow)
return None;
XMapWindow(dpy, window);
WaitEvent(dpy, window, MapNotify);
WaitEvent(dpy, window, Expose); /* XXX: workaround an XvBA init bug */
XFlush(dpy);
return window;
}
static void DestroyWindow(Display *dpy, Window window)
{
XUnmapWindow(dpy, window);
WaitEvent(dpy, window, UnmapNotify);
XDestroyWindow(dpy, window);
}
static Cursor CreateBlankCursor(vout_display_t *vd, Display *dpy,
Screen *screen)
{
vout_display_sys_t *sys = vd->sys;
assert(screen);
Colormap cmap;
Cursor no_ptr;
XColor dummy;
static char bm_no_data[] = {0, 0, 0, 0, 0, 0, 0, 0};
int scr = XScreenNumberOfScreen(screen);
cmap = DefaultColormap(dpy, scr);
XAllocNamedColor(dpy, cmap, "black", &sys->black, &dummy);
sys->bitmap = XCreateBitmapFromData(dpy, sys->window, bm_no_data, 8, 8);
no_ptr = XCreatePixmapCursor(dpy, sys->bitmap, sys->bitmap, &sys->black, &sys->black, 0, 0);
return no_ptr;
}
static void DestroyBlankCursor(vout_display_t *vd, Display *dpy,
Window window, Screen *screen)
{
vout_display_sys_t *sys = vd->sys;
assert(screen);
int scr = XScreenNumberOfScreen(screen);
Colormap cmap = DefaultColormap(dpy, scr);
XUndefineCursor(dpy, window);
XFreeCursor(dpy, sys->blank_cursor);
if (sys->bitmap != None)
XFreePixmap(dpy, sys->bitmap);
XFreeColors(dpy, cmap, &sys->black.pixel, 1, 0);
} }
/** /**
...@@ -387,20 +518,42 @@ int OpenVaapiX11 (vlc_object_t *obj) ...@@ -387,20 +518,42 @@ int OpenVaapiX11 (vlc_object_t *obj)
sys->render.i_cache = VA_INVALID_ID; sys->render.i_cache = VA_INVALID_ID;
sys->display.i_cache = VA_INVALID_ID; sys->display.i_cache = VA_INVALID_ID;
sys->visible = false; sys->embed = MakeWindow(vd);
if (unlikely(sys->embed == NULL))
goto error;
/* Create a VA display */ /* Create a VA display */
sys->conn = vlc_va_Initialize(NULL); sys->conn = vlc_va_Initialize(sys->embed->display.x11);
if (!sys->conn) if (!sys->conn)
goto error; goto error;
sys->embed = MakeWindow(vd); if (FindVAFourCC(vd) != VLC_SUCCESS)
if (unlikely(sys->embed == NULL))
goto error; goto error;
if (FindVAFourCC(vd) != VLC_SUCCESS) /* Find window parameters */
unsigned snum;
unsigned int depth;
unsigned int width, height;
int x, y;
sys->screen = FindScreen(vd, sys->conn->p_x11,
&x, &y, &snum, &depth,
&width, &height);
if (sys->screen == NULL)
goto error; goto error;
sys->geo.x = x;
sys->geo.y = y;
sys->geo.depth = depth;
sys->geo.width = width;
sys->geo.height = height;
sys->window = CreateWindow(vd, sys->conn->p_x11, sys->screen);
if (sys->window == None)
goto error;
sys->visible = false;
sys->blank_cursor = CreateBlankCursor(vd, sys->conn->p_x11, sys->screen);
msg_Info(vd, "using VAAPI X11 window (version %d.%d)", msg_Info(vd, "using VAAPI X11 window (version %d.%d)",
sys->conn->i_version_major, sys->conn->i_version_minor); sys->conn->i_version_major, sys->conn->i_version_minor);
...@@ -408,7 +561,7 @@ int OpenVaapiX11 (vlc_object_t *obj) ...@@ -408,7 +561,7 @@ int OpenVaapiX11 (vlc_object_t *obj)
vout_display_info_t info = vd->info; vout_display_info_t info = vd->info;
info.is_slow = false; info.is_slow = false;
info.has_pictures_invalid = false; info.has_pictures_invalid = false;
info.has_event_thread = false; info.has_event_thread = true;
info.has_hide_mouse = false; info.has_hide_mouse = false;
/* Setup vout_display_t once everything is fine */ /* Setup vout_display_t once everything is fine */
...@@ -426,20 +579,15 @@ int OpenVaapiX11 (vlc_object_t *obj) ...@@ -426,20 +579,15 @@ int OpenVaapiX11 (vlc_object_t *obj)
vd->pool = Pool; vd->pool = Pool;
vd->display = DisplayPicture; vd->display = DisplayPicture;
vd->control = Control; vd->control = Control;
vd->manage = NULL; //Manage; vd->manage = Manage;
vd->info = info; vd->info = info;
/* */ /* */
bool is_fullscreen = vd->cfg->is_fullscreen; bool is_fullscreen = vd->cfg->is_fullscreen;
if (is_fullscreen && vout_window_SetFullScreen (sys->embed, true)) if (is_fullscreen && vout_window_SetFullScreen(sys->embed, true))
is_fullscreen = false; is_fullscreen = false;
vout_display_SendEventFullscreen (vd, is_fullscreen); vout_display_SendEventFullscreen(vd, is_fullscreen);
unsigned int width, height; vout_display_SendEventDisplaySize(vd, width, height, is_fullscreen);
if (GetWindowSize(vd, &width, &height) == VLC_SUCCESS)
{
vout_window_SetSize (sys->embed, width, height);
vout_display_SendEventDisplaySize (vd, width, height, is_fullscreen);
}
return VLC_SUCCESS; return VLC_SUCCESS;
error: error:
...@@ -452,14 +600,25 @@ void CloseVaapiX11 (vlc_object_t *obj) ...@@ -452,14 +600,25 @@ void CloseVaapiX11 (vlc_object_t *obj)
vout_display_t *vd = (vout_display_t *) obj; vout_display_t *vd = (vout_display_t *) obj;
vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys; vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys;
if (sys->conn && sys->conn->p_x11) assert(sys->conn);
sys->conn->lock();
if (sys->conn->p_x11)
{ {
sys->conn->lock();
XFlush(sys->conn->p_x11); XFlush(sys->conn->p_x11);
XSync(sys->conn->p_x11, False); XSync(sys->conn->p_x11, False);
sys->conn->unlock();
} }
if (sys->blank_cursor != None)
DestroyBlankCursor(vd, sys->conn->p_x11,
sys->window, sys->screen);
if (sys->window != None)
DestroyWindow(sys->conn->p_x11, sys->window);
sys->blank_cursor = None;
sys->window = None;
sys->conn->unlock();
if (sys->embed) if (sys->embed)
vout_display_DeleteWindow (vd, sys->embed); vout_display_DeleteWindow (vd, sys->embed);
...@@ -502,14 +661,14 @@ static int Control (vout_display_t *vd, int query, va_list ap) ...@@ -502,14 +661,14 @@ static int Control (vout_display_t *vd, int query, va_list ap)
{ {
case VOUT_DISPLAY_CHANGE_FULLSCREEN: case VOUT_DISPLAY_CHANGE_FULLSCREEN:
{ {
const vout_display_cfg_t *c = va_arg (ap, const vout_display_cfg_t *); const vout_display_cfg_t *c = va_arg(ap, const vout_display_cfg_t *);
return vout_window_SetFullScreen (sys->embed, c->is_fullscreen); return vout_window_SetFullScreen(sys->embed, c->is_fullscreen);
} }
case VOUT_DISPLAY_CHANGE_WINDOW_STATE: case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
{ {
unsigned state = va_arg (ap, unsigned); unsigned state = va_arg(ap, unsigned);
return vout_window_SetState (sys->embed, state); return vout_window_SetState(sys->embed, state);
} }
case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
...@@ -525,26 +684,47 @@ static int Control (vout_display_t *vd, int query, va_list ap) ...@@ -525,26 +684,47 @@ static int Control (vout_display_t *vd, int query, va_list ap)
if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
|| query == VOUT_DISPLAY_CHANGE_SOURCE_CROP) || query == VOUT_DISPLAY_CHANGE_SOURCE_CROP)
{ {
source = (const video_format_t *)va_arg (ap, const video_format_t *); source = (const video_format_t *)va_arg(ap, const video_format_t *);
cfg = vd->cfg; cfg = vd->cfg;
} }
else else
{ {
source = &vd->source; source = &vd->source;
cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); cfg = (const vout_display_cfg_t*)va_arg(ap, const vout_display_cfg_t *);
if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE) if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
is_forced = (bool)va_arg (ap, int); is_forced = (bool)va_arg (ap, int);
} }
msg_Info(vd, "display size %dx%d %dx%d",
0, 0, cfg->display.width, cfg->display.height);
/* */ /* */
if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
&& is_forced && is_forced
&& (cfg->display.width != vd->cfg->display.width && (cfg->display.width != vd->cfg->display.width
||cfg->display.height != vd->cfg->display.height) ||cfg->display.height != vd->cfg->display.height)
&& vout_window_SetSize (sys->embed, && vout_window_SetSize(sys->embed,
cfg->display.width, cfg->display.height)) cfg->display.width, cfg->display.height))
return VLC_EGENERIC; return VLC_EGENERIC;
vout_display_place_t place;
vout_display_PlacePicture(&place, source, cfg, false);
/* */
sys->geo.x = place.x;
sys->geo.y = place.y;
sys->geo.width = place.width;
sys->geo.height = place.height;
XWindowChanges changes = { .x = place.x, .y = place.y,
.width = place.width, .height = place.height };
int err = XConfigureWindow(sys->conn->p_x11, sys->window,
CWX | CWY | CWWidth | CWHeight, &changes);
if (err == BadMatch || err == BadValue || err == BadWindow)
return VLC_EGENERIC;
msg_Info(vd, "New window size %dx%d %dx%d",
place.x, place.y, place.width, place.height);
return VLC_SUCCESS; return VLC_SUCCESS;
} }
case VOUT_DISPLAY_RESET_PICTURES: case VOUT_DISPLAY_RESET_PICTURES:
...@@ -556,8 +736,14 @@ static int Control (vout_display_t *vd, int query, va_list ap) ...@@ -556,8 +736,14 @@ static int Control (vout_display_t *vd, int query, va_list ap)
/* Hide the mouse. It will be send when /* Hide the mouse. It will be send when
* vout_display_t::info.b_hide_mouse is false */ * vout_display_t::info.b_hide_mouse is false */
case VOUT_DISPLAY_HIDE_MOUSE: case VOUT_DISPLAY_HIDE_MOUSE:
/* FIXME */ {
int err = XDefineCursor(sys->conn->p_x11, sys->window,
sys->blank_cursor);
if (err == BadAlloc || err == BadWindow || err == BadCursor)
return VLC_EGENERIC;
return VLC_SUCCESS; return VLC_SUCCESS;
}
default: default:
msg_Err (vd, "Unknown request in XCB vout display"); msg_Err (vd, "Unknown request in XCB vout display");
...@@ -565,6 +751,100 @@ static int Control (vout_display_t *vd, int query, va_list ap) ...@@ -565,6 +751,100 @@ static int Control (vout_display_t *vd, int query, va_list ap)
} }
} }
static int HandleEvent(vout_display_t *vd, Display *dpy, XEvent *event,
bool *visible)
{
vout_display_sys_t *sys = vd->sys;
switch(event->type)
{
case ButtonPress:
{
XButtonEvent *ev = (XButtonEvent *)event;
vout_display_SendEventMousePressed(vd, ev->button - 1);
break;
}
case ButtonRelease:
{
XButtonEvent *ev = (XButtonEvent *)event;
vout_display_SendEventMouseReleased(vd, ev->button - 1);
break;
}
case MotionNotify:
{
XMotionEvent *ev = (XMotionEvent *)event;
vout_display_place_t place;
/* show the default cursor */
XUndefineCursor(dpy, sys->window);
/* TODO it could be saved */
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
if (place.width <= 0 || place.height <= 0)
return VLC_EGENERIC;
const int x = vd->source.i_x_offset +
(int64_t)(ev->x - place.x) * vd->source.i_visible_width / place.width;
const int y = vd->source.i_y_offset +
(int64_t)(ev->y - place.y) * vd->source.i_visible_height/ place.height;
vout_display_SendEventMouseMoved(vd, x, y);
break;
}
case VisibilityNotify:
{
XVisibilityEvent *ev = (XVisibilityEvent *)event;
*visible = ev->state != VisibilityFullyObscured;
msg_Dbg (vd, "display is %svisible", *visible ? "" : "not ");
break;
}
case ConfigureNotify:
{
XConfigureEvent *ev = (XConfigureEvent *)event;
vout_display_SendEventDisplaySize(vd, ev->width, ev->height,
vd->cfg->is_fullscreen);
break;
}
case ConfigureRequest:
{
XConfigureRequestEvent *ev = (XConfigureRequestEvent *)event;
vout_display_SendEventDisplaySize(vd, ev->width, ev->height,
vd->cfg->is_fullscreen);
break;
}
case ResizeRequest:
{
XResizeRequestEvent *ev = (XResizeRequestEvent *)event;
vout_display_SendEventDisplaySize(vd, ev->width, ev->height,
vd->cfg->is_fullscreen);
break;
}
case DestroyNotify:
vout_display_SendEventClose(vd);
break;
case Expose:
case MappingNotify:
break;
default:
msg_Err(vd, "unhandled event %d", event->type);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
static void Manage(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
while (XPending(sys->conn->p_x11))
{
XEvent event;
XNextEvent(sys->conn->p_x11, &event);
HandleEvent(vd, sys->conn->p_x11, &event, &sys->visible);
}
}
static VASubpictureID SubpictureCreate(vout_display_t *vd, const subpicture_t *subpicture, static VASubpictureID SubpictureCreate(vout_display_t *vd, const subpicture_t *subpicture,
const subpicture_region_t *region, VAImage *image, const int flags) const subpicture_region_t *region, VAImage *image, const int flags)
{ {
...@@ -1139,16 +1419,13 @@ static void DisplayVASurface(vout_display_t *vd, VASurfaceID surface, picture_t ...@@ -1139,16 +1419,13 @@ static void DisplayVASurface(vout_display_t *vd, VASurfaceID surface, picture_t
{ {
vout_display_sys_t *sys = vd->sys; vout_display_sys_t *sys = vd->sys;
vout_display_place_t place;
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
sys->conn->lock(); sys->conn->lock();
VAStatus status; VAStatus status;
status = vaPutSurface(sys->conn->p_display, surface, sys->embed->handle.xid, status = vaPutSurface(sys->conn->p_display, surface, sys->window,
picture->format.i_x_offset, picture->format.i_y_offset, vd->source.i_x_offset, vd->source.i_y_offset,
picture->format.i_visible_width, picture->format.i_visible_height, vd->source.i_visible_width, vd->source.i_visible_height,
place.x, place.y, place.width, place.height, sys->geo.x, sys->geo.y, sys->geo.width, sys->geo.height,
NULL, 0, /* clipping */ NULL, 0, /* clipping */
/* NOTE: vaCreateContext() specifies VA_PROGRESSIVE */ /* NOTE: vaCreateContext() specifies VA_PROGRESSIVE */
picture->b_progressive ? VA_FRAME_PICTURE : picture->b_progressive ? VA_FRAME_PICTURE :
...@@ -1165,15 +1442,15 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub ...@@ -1165,15 +1442,15 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
{ {
vout_display_sys_t *sys = vd->sys; vout_display_sys_t *sys = vd->sys;
if (!sys->visible)
goto out;
assert(pic->format.i_chroma == VLC_CODEC_VAAPI_SURFACE); assert(pic->format.i_chroma == VLC_CODEC_VAAPI_SURFACE);
if ((pic->p_sys == NULL) || (pic->p_sys->i_id == VA_INVALID_SURFACE)) if ((pic->p_sys == NULL) || (pic->p_sys->i_id == VA_INVALID_SURFACE))
{ {
msg_Err(vd, "discarding picture without picture_sys_t information"); msg_Err(vd, "discarding picture without picture_sys_t information");
if (subpicture) goto out;
subpicture_Delete(subpicture);
picture_Release(pic);
return;
} }
picture_sys_t *surface = pic->p_sys; picture_sys_t *surface = pic->p_sys;
...@@ -1209,7 +1486,7 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub ...@@ -1209,7 +1486,7 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
/* */ /* */
sys->display.i_cache = surface->i_cache; sys->display.i_cache = surface->i_cache;
out:
if (subpicture) if (subpicture)
subpicture_Delete(subpicture); subpicture_Delete(subpicture);
...@@ -1268,8 +1545,6 @@ static void PictureUnlock(picture_t *picture) ...@@ -1268,8 +1545,6 @@ static void PictureUnlock(picture_t *picture)
if (surface->i_refcount > 0) if (surface->i_refcount > 0)
surface->i_refcount--; surface->i_refcount--;
//assert(surface->i_refcount == 0);
//surface->i_refcount = 0;
surface->i_cache = VA_INVALID_ID; surface->i_cache = VA_INVALID_ID;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment