/** * Process __DRIbuffer and convert them into pipe_resources. */ static void dri2_drawable_process_buffers(struct dri_context *ctx, struct dri_drawable *drawable, __DRIbuffer *buffers, unsigned buffer_count, const enum st_attachment_type *atts, unsigned att_count) { struct dri_screen *screen = dri_screen(drawable->sPriv); __DRIdrawable *dri_drawable = drawable->dPriv; struct pipe_resource templ; struct winsys_handle whandle; boolean alloc_depthstencil = FALSE; unsigned i, j, bind; if (drawable->old_num == buffer_count && drawable->old_w == dri_drawable->w && drawable->old_h == dri_drawable->h && memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * buffer_count) == 0) return; /* See if we need a depth-stencil buffer. */ for (i = 0; i < att_count; i++) { if (atts[i] == ST_ATTACHMENT_DEPTH_STENCIL) { alloc_depthstencil = TRUE; break; } } /* Delete the resources we won't need. */ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { /* Don't delete the depth-stencil buffer, we can reuse it. */ if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil) continue; /* Flush the texture before unreferencing, so that other clients can * see what the driver has rendered. */ if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) { struct pipe_context *pipe = ctx->st->pipe; pipe->flush_resource(pipe, drawable->textures[i]); } pipe_resource_reference(&drawable->textures[i], NULL); } if (drawable->stvis.samples > 1) { for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { boolean del = TRUE; /* Don't delete MSAA resources for the attachments which are enabled, * we can reuse them. */ for (j = 0; j < att_count; j++) { if (i == atts[j]) { del = FALSE; break; } } if (del) { pipe_resource_reference(&drawable->msaa_textures[i], NULL); } } } memset(&templ, 0, sizeof(templ)); templ.target = screen->target; templ.last_level = 0; templ.width0 = dri_drawable->w; templ.height0 = dri_drawable->h; templ.depth0 = 1; templ.array_size = 1; memset(&whandle, 0, sizeof(whandle)); /* Process DRI-provided buffers and get pipe_resources. */ for (i = 0; i < buffer_count; i++) { __DRIbuffer *buf = &buffers[i]; enum st_attachment_type statt; enum pipe_format format; switch (buf->attachment) { case __DRI_BUFFER_FRONT_LEFT: if (!screen->auto_fake_front) { continue; /* invalid attachment */ } /* fallthrough */ case __DRI_BUFFER_FAKE_FRONT_LEFT: statt = ST_ATTACHMENT_FRONT_LEFT; break; case __DRI_BUFFER_BACK_LEFT: statt = ST_ATTACHMENT_BACK_LEFT; break; default: continue; /* invalid attachment */ } dri_drawable_get_format(drawable, statt, &format, &bind); if (format == PIPE_FORMAT_NONE) continue; templ.format = format; templ.bind = bind; whandle.type = DRM_API_HANDLE_TYPE_SHARED; whandle.handle = buf->name; whandle.stride = buf->pitch; drawable->textures[statt] = screen->base.screen->resource_from_handle(screen->base.screen, &templ, &whandle); assert(drawable->textures[statt]); } /* Allocate private MSAA colorbuffers. */ if (drawable->stvis.samples > 1) { for (i = 0; i < att_count; i++) { enum st_attachment_type att = atts[i]; if (att == ST_ATTACHMENT_DEPTH_STENCIL) continue; if (drawable->textures[att]) { templ.format = drawable->textures[att]->format; templ.bind = drawable->textures[att]->bind; templ.nr_samples = drawable->stvis.samples; /* Try to reuse the resource. * (the other resource parameters should be constant) */ if (!drawable->msaa_textures[att] || drawable->msaa_textures[att]->width0 != templ.width0 || drawable->msaa_textures[att]->height0 != templ.height0) { /* Allocate a new one. */ pipe_resource_reference(&drawable->msaa_textures[att], NULL); drawable->msaa_textures[att] = screen->base.screen->resource_create(screen->base.screen, &templ); assert(drawable->msaa_textures[att]); /* If there are any MSAA resources, we should initialize them * such that they contain the same data as the single-sample * resources we just got from the X server. * * The reason for this is that the state tracker (and * therefore the app) can access the MSAA resources only. * The single-sample resources are not exposed * to the state tracker. * */ dri_pipe_blit(ctx->st->pipe, drawable->msaa_textures[att], drawable->textures[att]); } } else { pipe_resource_reference(&drawable->msaa_textures[att], NULL); } } } /* Allocate a private depth-stencil buffer. */ if (alloc_depthstencil) { enum st_attachment_type att = ST_ATTACHMENT_DEPTH_STENCIL; struct pipe_resource **zsbuf; enum pipe_format format; unsigned bind; dri_drawable_get_format(drawable, att, &format, &bind); if (format) { templ.format = format; templ.bind = bind; if (drawable->stvis.samples > 1) { templ.nr_samples = drawable->stvis.samples; zsbuf = &drawable->msaa_textures[att]; } else { templ.nr_samples = 0; zsbuf = &drawable->textures[att]; } /* Try to reuse the resource. * (the other resource parameters should be constant) */ if (!*zsbuf || (*zsbuf)->width0 != templ.width0 || (*zsbuf)->height0 != templ.height0) { /* Allocate a new one. */ pipe_resource_reference(zsbuf, NULL); *zsbuf = screen->base.screen->resource_create(screen->base.screen, &templ); assert(*zsbuf); } } else { pipe_resource_reference(&drawable->msaa_textures[att], NULL); pipe_resource_reference(&drawable->textures[att], NULL); } } drawable->old_num = buffer_count; drawable->old_w = dri_drawable->w; drawable->old_h = dri_drawable->h; memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * buffer_count); }
static __DRIimage * dri2_create_image_from_winsys(__DRIscreen *_screen, int width, int height, int format, struct winsys_handle *whandle, int pitch, void *loaderPrivate) { struct dri_screen *screen = dri_screen(_screen); __DRIimage *img; struct pipe_resource templ; unsigned tex_usage; enum pipe_format pf; tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; switch (format) { case __DRI_IMAGE_FORMAT_RGB565: pf = PIPE_FORMAT_B5G6R5_UNORM; break; case __DRI_IMAGE_FORMAT_XRGB8888: pf = PIPE_FORMAT_B8G8R8X8_UNORM; break; case __DRI_IMAGE_FORMAT_ARGB8888: pf = PIPE_FORMAT_B8G8R8A8_UNORM; break; case __DRI_IMAGE_FORMAT_ABGR8888: pf = PIPE_FORMAT_R8G8B8A8_UNORM; break; default: pf = PIPE_FORMAT_NONE; break; } if (pf == PIPE_FORMAT_NONE) return NULL; img = CALLOC_STRUCT(__DRIimageRec); if (!img) return NULL; memset(&templ, 0, sizeof(templ)); templ.bind = tex_usage; templ.format = pf; templ.target = screen->target; templ.last_level = 0; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; templ.array_size = 1; whandle->stride = pitch * util_format_get_blocksize(pf); img->texture = screen->base.screen->resource_from_handle(screen->base.screen, &templ, whandle); if (!img->texture) { FREE(img); return NULL; } img->level = 0; img->layer = 0; img->dri_format = format; img->loader_private = loaderPrivate; return img; }
static __DRIimage * dri2_create_image(__DRIscreen *_screen, int width, int height, int format, unsigned int use, void *loaderPrivate) { struct dri_screen *screen = dri_screen(_screen); __DRIimage *img; struct pipe_resource templ; unsigned tex_usage; enum pipe_format pf; tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; if (use & __DRI_IMAGE_USE_SCANOUT) tex_usage |= PIPE_BIND_SCANOUT; if (use & __DRI_IMAGE_USE_SHARE) tex_usage |= PIPE_BIND_SHARED; if (use & __DRI_IMAGE_USE_LINEAR) tex_usage |= PIPE_BIND_LINEAR; if (use & __DRI_IMAGE_USE_CURSOR) { if (width != 64 || height != 64) return NULL; tex_usage |= PIPE_BIND_CURSOR; } switch (format) { case __DRI_IMAGE_FORMAT_RGB565: pf = PIPE_FORMAT_B5G6R5_UNORM; break; case __DRI_IMAGE_FORMAT_XRGB8888: pf = PIPE_FORMAT_B8G8R8X8_UNORM; break; case __DRI_IMAGE_FORMAT_ARGB8888: pf = PIPE_FORMAT_B8G8R8A8_UNORM; break; case __DRI_IMAGE_FORMAT_ABGR8888: pf = PIPE_FORMAT_R8G8B8A8_UNORM; break; default: pf = PIPE_FORMAT_NONE; break; } if (pf == PIPE_FORMAT_NONE) return NULL; img = CALLOC_STRUCT(__DRIimageRec); if (!img) return NULL; memset(&templ, 0, sizeof(templ)); templ.bind = tex_usage; templ.format = pf; templ.target = PIPE_TEXTURE_2D; templ.last_level = 0; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; templ.array_size = 1; img->texture = screen->base.screen->resource_create(screen->base.screen, &templ); if (!img->texture) { FREE(img); return NULL; } img->level = 0; img->layer = 0; img->dri_format = format; img->dri_components = 0; img->loader_private = loaderPrivate; return img; }
static __DRIbuffer * dri2_allocate_buffer(__DRIscreen *sPriv, unsigned attachment, unsigned format, int width, int height) { struct dri_screen *screen = dri_screen(sPriv); struct dri2_buffer *buffer; struct pipe_resource templ; enum pipe_format pf; unsigned bind = 0; struct winsys_handle whandle; switch (attachment) { case __DRI_BUFFER_FRONT_LEFT: case __DRI_BUFFER_FAKE_FRONT_LEFT: bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; break; case __DRI_BUFFER_BACK_LEFT: bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; break; case __DRI_BUFFER_DEPTH: case __DRI_BUFFER_DEPTH_STENCIL: case __DRI_BUFFER_STENCIL: bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ break; } /* because we get the handle and stride */ bind |= PIPE_BIND_SHARED; switch (format) { case 32: pf = PIPE_FORMAT_B8G8R8A8_UNORM; break; case 24: pf = PIPE_FORMAT_B8G8R8X8_UNORM; break; case 16: pf = PIPE_FORMAT_Z16_UNORM; break; default: return NULL; } buffer = CALLOC_STRUCT(dri2_buffer); if (!buffer) return NULL; memset(&templ, 0, sizeof(templ)); templ.bind = bind; templ.format = pf; templ.target = PIPE_TEXTURE_2D; templ.last_level = 0; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; templ.array_size = 1; buffer->resource = screen->base.screen->resource_create(screen->base.screen, &templ); if (!buffer->resource) { FREE(buffer); return NULL; } memset(&whandle, 0, sizeof(whandle)); if (screen->can_share_buffer) whandle.type = DRM_API_HANDLE_TYPE_SHARED; else whandle.type = DRM_API_HANDLE_TYPE_KMS; screen->base.screen->resource_get_handle(screen->base.screen, buffer->resource, &whandle); buffer->base.attachment = attachment; buffer->base.name = whandle.handle; buffer->base.cpp = util_format_get_blocksize(pf); buffer->base.pitch = whandle.stride; return &buffer->base; }
static void dri2_allocate_textures(struct dri_context *ctx, struct dri_drawable *drawable, const enum st_attachment_type *statts, unsigned statts_count) { __DRIscreen *sPriv = drawable->sPriv; __DRIdrawable *dri_drawable = drawable->dPriv; struct dri_screen *screen = dri_screen(sPriv); struct pipe_resource templ; boolean alloc_depthstencil = FALSE; unsigned i, j, bind; const __DRIimageLoaderExtension *image = sPriv->image.loader; /* Image specific variables */ struct __DRIimageList images; /* Dri2 specific variables */ __DRIbuffer *buffers; struct winsys_handle whandle; unsigned num_buffers = statts_count; /* First get the buffers from the loader */ if (image) { if (!dri_image_drawable_get_buffers(drawable, &images, statts, statts_count)) return; } else { buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers); if (!buffers || (drawable->old_num == num_buffers && drawable->old_w == dri_drawable->w && drawable->old_h == dri_drawable->h && memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers) == 0)) return; } /* Second clean useless resources*/ /* See if we need a depth-stencil buffer. */ for (i = 0; i < statts_count; i++) { if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) { alloc_depthstencil = TRUE; break; } } /* Delete the resources we won't need. */ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { /* Don't delete the depth-stencil buffer, we can reuse it. */ if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil) continue; /* Flush the texture before unreferencing, so that other clients can * see what the driver has rendered. */ if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) { struct pipe_context *pipe = ctx->st->pipe; pipe->flush_resource(pipe, drawable->textures[i]); } pipe_resource_reference(&drawable->textures[i], NULL); } if (drawable->stvis.samples > 1) { for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { boolean del = TRUE; /* Don't delete MSAA resources for the attachments which are enabled, * we can reuse them. */ for (j = 0; j < statts_count; j++) { if (i == statts[j]) { del = FALSE; break; } } if (del) { pipe_resource_reference(&drawable->msaa_textures[i], NULL); } } } /* Third use the buffers retrieved to fill the drawable info */ memset(&templ, 0, sizeof(templ)); templ.target = screen->target; templ.last_level = 0; templ.depth0 = 1; templ.array_size = 1; if (image) { if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) { struct pipe_resource **buf = &drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; struct pipe_resource *texture = images.front->texture; dri_drawable->w = texture->width0; dri_drawable->h = texture->height0; pipe_resource_reference(buf, texture); } if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) { struct pipe_resource **buf = &drawable->textures[ST_ATTACHMENT_BACK_LEFT]; struct pipe_resource *texture = images.back->texture; dri_drawable->w = texture->width0; dri_drawable->h = texture->height0; pipe_resource_reference(buf, texture); } /* Note: if there is both a back and a front buffer, * then they have the same size. */ templ.width0 = dri_drawable->w; templ.height0 = dri_drawable->h; } else { memset(&whandle, 0, sizeof(whandle)); /* Process DRI-provided buffers and get pipe_resources. */ for (i = 0; i < num_buffers; i++) { __DRIbuffer *buf = &buffers[i]; enum st_attachment_type statt; enum pipe_format format; switch (buf->attachment) { case __DRI_BUFFER_FRONT_LEFT: if (!screen->auto_fake_front) { continue; /* invalid attachment */ } /* fallthrough */ case __DRI_BUFFER_FAKE_FRONT_LEFT: statt = ST_ATTACHMENT_FRONT_LEFT; break; case __DRI_BUFFER_BACK_LEFT: statt = ST_ATTACHMENT_BACK_LEFT; break; default: continue; /* invalid attachment */ } dri_drawable_get_format(drawable, statt, &format, &bind); if (format == PIPE_FORMAT_NONE) continue; /* dri2_drawable_get_buffers has already filled dri_drawable->w * and dri_drawable->h */ templ.width0 = dri_drawable->w; templ.height0 = dri_drawable->h; templ.format = format; templ.bind = bind; whandle.handle = buf->name; whandle.stride = buf->pitch; if (screen->can_share_buffer) whandle.type = DRM_API_HANDLE_TYPE_SHARED; else whandle.type = DRM_API_HANDLE_TYPE_KMS; drawable->textures[statt] = screen->base.screen->resource_from_handle(screen->base.screen, &templ, &whandle); assert(drawable->textures[statt]); } } /* Allocate private MSAA colorbuffers. */ if (drawable->stvis.samples > 1) { for (i = 0; i < statts_count; i++) { enum st_attachment_type statt = statts[i]; if (statt == ST_ATTACHMENT_DEPTH_STENCIL) continue; if (drawable->textures[statt]) { templ.format = drawable->textures[statt]->format; templ.bind = drawable->textures[statt]->bind; templ.nr_samples = drawable->stvis.samples; /* Try to reuse the resource. * (the other resource parameters should be constant) */ if (!drawable->msaa_textures[statt] || drawable->msaa_textures[statt]->width0 != templ.width0 || drawable->msaa_textures[statt]->height0 != templ.height0) { /* Allocate a new one. */ pipe_resource_reference(&drawable->msaa_textures[statt], NULL); drawable->msaa_textures[statt] = screen->base.screen->resource_create(screen->base.screen, &templ); assert(drawable->msaa_textures[statt]); /* If there are any MSAA resources, we should initialize them * such that they contain the same data as the single-sample * resources we just got from the X server. * * The reason for this is that the state tracker (and * therefore the app) can access the MSAA resources only. * The single-sample resources are not exposed * to the state tracker. * */ dri_pipe_blit(ctx->st->pipe, drawable->msaa_textures[statt], drawable->textures[statt]); } } else { pipe_resource_reference(&drawable->msaa_textures[statt], NULL); } } } /* Allocate a private depth-stencil buffer. */ if (alloc_depthstencil) { enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL; struct pipe_resource **zsbuf; enum pipe_format format; unsigned bind; dri_drawable_get_format(drawable, statt, &format, &bind); if (format) { templ.format = format; templ.bind = bind; if (drawable->stvis.samples > 1) { templ.nr_samples = drawable->stvis.samples; zsbuf = &drawable->msaa_textures[statt]; } else { templ.nr_samples = 0; zsbuf = &drawable->textures[statt]; } /* Try to reuse the resource. * (the other resource parameters should be constant) */ if (!*zsbuf || (*zsbuf)->width0 != templ.width0 || (*zsbuf)->height0 != templ.height0) { /* Allocate a new one. */ pipe_resource_reference(zsbuf, NULL); *zsbuf = screen->base.screen->resource_create(screen->base.screen, &templ); assert(*zsbuf); } } else { pipe_resource_reference(&drawable->msaa_textures[statt], NULL); pipe_resource_reference(&drawable->textures[statt], NULL); } } /* For DRI2, we may get the same buffers again from the server. * To prevent useless imports of gem names, drawable->old* is used * to bypass the import if we get the same buffers. This doesn't apply * to DRI3/Wayland, users of image.loader, since the buffer is managed * by the client (no import), and the back buffer is going to change * at every redraw. */ if (!image) { drawable->old_num = num_buffers; drawable->old_w = dri_drawable->w; drawable->old_h = dri_drawable->h; memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers); } }
/** * Process __DRIbuffer and convert them into pipe_resources. */ static void dri2_drawable_process_buffers(struct dri_drawable *drawable, __DRIbuffer *buffers, unsigned count) { struct dri_screen *screen = dri_screen(drawable->sPriv); __DRIdrawable *dri_drawable = drawable->dPriv; struct pipe_resource templ; struct winsys_handle whandle; boolean have_depth = FALSE; unsigned i, bind; if (drawable->old_num == count && drawable->old_w == dri_drawable->w && drawable->old_h == dri_drawable->h && memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0) return; for (i = 0; i < ST_ATTACHMENT_COUNT; i++) pipe_resource_reference(&drawable->textures[i], NULL); memset(&templ, 0, sizeof(templ)); templ.target = screen->target; templ.last_level = 0; templ.width0 = dri_drawable->w; templ.height0 = dri_drawable->h; templ.depth0 = 1; templ.array_size = 1; memset(&whandle, 0, sizeof(whandle)); for (i = 0; i < count; i++) { __DRIbuffer *buf = &buffers[i]; enum st_attachment_type statt; enum pipe_format format; switch (buf->attachment) { case __DRI_BUFFER_FRONT_LEFT: if (!screen->auto_fake_front) { statt = ST_ATTACHMENT_INVALID; break; } /* fallthrough */ case __DRI_BUFFER_FAKE_FRONT_LEFT: statt = ST_ATTACHMENT_FRONT_LEFT; break; case __DRI_BUFFER_BACK_LEFT: statt = ST_ATTACHMENT_BACK_LEFT; break; case __DRI_BUFFER_DEPTH: case __DRI_BUFFER_DEPTH_STENCIL: case __DRI_BUFFER_STENCIL: /* use only the first depth/stencil buffer */ if (!have_depth) { have_depth = TRUE; statt = ST_ATTACHMENT_DEPTH_STENCIL; } else { statt = ST_ATTACHMENT_INVALID; } break; default: statt = ST_ATTACHMENT_INVALID; break; } dri_drawable_get_format(drawable, statt, &format, &bind); if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE) continue; templ.format = format; templ.bind = bind; whandle.handle = buf->name; whandle.stride = buf->pitch; drawable->textures[statt] = screen->base.screen->resource_from_handle(screen->base.screen, &templ, &whandle); } drawable->old_num = count; drawable->old_w = dri_drawable->w; drawable->old_h = dri_drawable->h; memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count); }
/** * DRI2 flush extension, the flush_with_flags function. * * \param context the context * \param drawable the drawable to flush * \param flags a combination of _DRI2_FLUSH_xxx flags * \param throttle_reason the reason for throttling, 0 = no throttling */ void dri_flush(__DRIcontext *cPriv, __DRIdrawable *dPriv, unsigned flags, enum __DRI2throttleReason reason) { struct dri_context *ctx = dri_context(cPriv); struct dri_drawable *drawable = dri_drawable(dPriv); struct st_context_iface *st; unsigned flush_flags; boolean swap_msaa_buffers = FALSE; if (!ctx) { assert(0); return; } st = ctx->st; if (st->thread_finish) st->thread_finish(st); if (drawable) { /* prevent recursion */ if (drawable->flushing) return; drawable->flushing = TRUE; } else { flags &= ~__DRI2_FLUSH_DRAWABLE; } /* Flush the drawable. */ if ((flags & __DRI2_FLUSH_DRAWABLE) && drawable->textures[ST_ATTACHMENT_BACK_LEFT]) { struct pipe_context *pipe = st->pipe; if (drawable->stvis.samples > 1 && reason == __DRI2_THROTTLE_SWAPBUFFER) { /* Resolve the MSAA back buffer. */ dri_pipe_blit(st->pipe, drawable->textures[ST_ATTACHMENT_BACK_LEFT], drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]); if (drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] && drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) { swap_msaa_buffers = TRUE; } /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */ } dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT); if (ctx->hud) { hud_draw(ctx->hud, drawable->textures[ST_ATTACHMENT_BACK_LEFT]); } pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_BACK_LEFT]); if (pipe->invalidate_resource && (flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) { if (drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) pipe->invalidate_resource(pipe, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); if (drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]) pipe->invalidate_resource(pipe, drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]); } } flush_flags = 0; if (flags & __DRI2_FLUSH_CONTEXT) flush_flags |= ST_FLUSH_FRONT; if (reason == __DRI2_THROTTLE_SWAPBUFFER) flush_flags |= ST_FLUSH_END_OF_FRAME; /* Flush the context and throttle if needed. */ if (dri_screen(ctx->sPriv)->throttling_enabled && drawable && (reason == __DRI2_THROTTLE_SWAPBUFFER || reason == __DRI2_THROTTLE_FLUSHFRONT)) { /* Throttle. * * This pulls a fence off the throttling queue and waits for it if the * number of fences on the throttling queue has reached the desired * number. * * Then flushes to insert a fence at the current rendering position, and * pushes that fence on the queue. This requires that the st_context_iface * flush method returns a fence even if there are no commands to flush. */ struct pipe_screen *screen = drawable->screen->base.screen; struct pipe_fence_handle *fence; fence = swap_fences_pop_front(drawable); if (fence) { (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE); screen->fence_reference(screen, &fence, NULL); } st->flush(st, flush_flags, &fence); if (fence) { swap_fences_push_back(drawable, fence); screen->fence_reference(screen, &fence, NULL); } } else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) { st->flush(st, flush_flags, NULL); } if (drawable) { drawable->flushing = FALSE; } /* Swap the MSAA front and back buffers, so that reading * from the front buffer after SwapBuffers returns what was * in the back buffer. */ if (swap_msaa_buffers) { struct pipe_resource *tmp = drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]; drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] = drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]; drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp; /* Now that we have swapped the buffers, this tells the state * tracker to revalidate the framebuffer. */ p_atomic_inc(&drawable->base.stamp); } }
static boolean dri_st_framebuffer_validate(struct st_context_iface *stctx, struct st_framebuffer_iface *stfbi, const enum st_attachment_type *statts, unsigned count, struct pipe_resource **out) { struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private; struct dri_drawable *drawable = (struct dri_drawable *) stfbi->st_manager_private; struct dri_screen *screen = dri_screen(drawable->sPriv); unsigned statt_mask, new_mask; boolean new_stamp; int i; unsigned int lastStamp; struct pipe_resource **textures = drawable->stvis.samples > 1 ? drawable->msaa_textures : drawable->textures; statt_mask = 0x0; for (i = 0; i < count; i++) statt_mask |= (1 << statts[i]); /* record newly allocated textures */ new_mask = (statt_mask & ~drawable->texture_mask); /* * dPriv->dri2.stamp is the server stamp. dPriv->lastStamp is the * client stamp. It has the value of the server stamp when last * checked. */ do { lastStamp = drawable->dPriv->lastStamp; new_stamp = (drawable->texture_stamp != lastStamp); if (new_stamp || new_mask || screen->broken_invalidate) { if (new_stamp && drawable->update_drawable_info) drawable->update_drawable_info(drawable); drawable->allocate_textures(ctx, drawable, statts, count); /* add existing textures */ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { if (textures[i]) statt_mask |= (1 << i); } drawable->texture_stamp = lastStamp; drawable->texture_mask = statt_mask; } } while (lastStamp != drawable->dPriv->lastStamp); if (!out) return TRUE; /* Set the window-system buffers for the state tracker. */ for (i = 0; i < count; i++) { out[i] = NULL; pipe_resource_reference(&out[i], textures[statts[i]]); } return TRUE; }
/** * Allocate framebuffer attachments. * * During fixed-size operation, the function keeps allocating new attachments * as they are requested. Unused attachments are not removed, not until the * framebuffer is resized or destroyed. */ static void drisw_allocate_textures(struct dri_context *stctx, struct dri_drawable *drawable, const enum st_attachment_type *statts, unsigned count) { struct dri_screen *screen = dri_screen(drawable->sPriv); const __DRIswrastLoaderExtension *loader = drawable->dPriv->driScreenPriv->swrast_loader; struct pipe_resource templ; unsigned width, height; boolean resized; unsigned i; width = drawable->dPriv->w; height = drawable->dPriv->h; resized = (drawable->old_w != width || drawable->old_h != height); /* remove outdated textures */ if (resized) { for (i = 0; i < ST_ATTACHMENT_COUNT; i++) pipe_resource_reference(&drawable->textures[i], NULL); } memset(&templ, 0, sizeof(templ)); templ.target = screen->target; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; templ.array_size = 1; templ.last_level = 0; for (i = 0; i < count; i++) { enum pipe_format format; unsigned bind; /* the texture already exists or not requested */ if (drawable->textures[statts[i]]) continue; dri_drawable_get_format(drawable, statts[i], &format, &bind); /* if we don't do any present, no need for display targets */ if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present) bind |= PIPE_BIND_DISPLAY_TARGET; if (format == PIPE_FORMAT_NONE) continue; templ.format = format; templ.bind = bind; if (statts[i] == ST_ATTACHMENT_FRONT_LEFT && screen->base.screen->resource_create_front && loader->base.version >= 3) { drawable->textures[statts[i]] = screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable); } else drawable->textures[statts[i]] = screen->base.screen->resource_create(screen->base.screen, &templ); } drawable->old_w = width; drawable->old_h = height; }
GLboolean dri_create_context(gl_api api, const struct gl_config * visual, __DRIcontext * cPriv, unsigned major_version, unsigned minor_version, uint32_t flags, unsigned *error, void *sharedContextPrivate) { __DRIscreen *sPriv = cPriv->driScreenPriv; struct dri_screen *screen = dri_screen(sPriv); struct st_api *stapi = screen->st_api; struct dri_context *ctx = NULL; struct st_context_iface *st_share = NULL; struct st_context_attribs attribs; enum st_context_error ctx_err = 0; memset(&attribs, 0, sizeof(attribs)); switch (api) { case API_OPENGLES: attribs.profile = ST_PROFILE_OPENGL_ES1; break; case API_OPENGLES2: attribs.profile = ST_PROFILE_OPENGL_ES2; break; case API_OPENGL: attribs.profile = ST_PROFILE_DEFAULT; attribs.major = major_version; attribs.minor = minor_version; if ((flags & __DRI_CTX_FLAG_DEBUG) != 0) attribs.flags |= ST_CONTEXT_FLAG_DEBUG; if ((flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE; break; default: *error = __DRI_CTX_ERROR_BAD_API; goto fail; } if (sharedContextPrivate) { st_share = ((struct dri_context *)sharedContextPrivate)->st; } ctx = CALLOC_STRUCT(dri_context); if (ctx == NULL) { *error = __DRI_CTX_ERROR_NO_MEMORY; goto fail; } cPriv->driverPrivate = ctx; ctx->cPriv = cPriv; ctx->sPriv = sPriv; driParseConfigFiles(&ctx->optionCache, &screen->optionCache, sPriv->myNum, driver_descriptor.name); dri_fill_st_options(&attribs.options, &ctx->optionCache); dri_fill_st_visual(&attribs.visual, screen, visual); ctx->st = stapi->create_context(stapi, &screen->base, &attribs, &ctx_err, st_share); if (ctx->st == NULL) { switch (ctx_err) { case ST_CONTEXT_SUCCESS: *error = __DRI_CTX_ERROR_SUCCESS; break; case ST_CONTEXT_ERROR_NO_MEMORY: *error = __DRI_CTX_ERROR_NO_MEMORY; break; case ST_CONTEXT_ERROR_BAD_API: *error = __DRI_CTX_ERROR_BAD_API; break; case ST_CONTEXT_ERROR_BAD_VERSION: *error = __DRI_CTX_ERROR_BAD_VERSION; break; case ST_CONTEXT_ERROR_BAD_FLAG: *error = __DRI_CTX_ERROR_BAD_FLAG; break; case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE: *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; break; case ST_CONTEXT_ERROR_UNKNOWN_FLAG: *error = __DRI_CTX_ERROR_UNKNOWN_FLAG; break; } goto fail; } ctx->st->st_manager_private = (void *) ctx; ctx->stapi = stapi; // Context successfully created. See if post-processing is requested. dri_pp_query(ctx); ctx->pp = pp_init(screen->base.screen, ctx->pp_enabled); *error = __DRI_CTX_ERROR_SUCCESS; return GL_TRUE; fail: if (ctx && ctx->st) ctx->st->destroy(ctx->st); FREE(ctx); return GL_FALSE; }