summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Versace <chadversary@chromium.org>2018-04-10 23:22:03 -0700
committerChad Versace <chadversary@chromium.org>2018-05-01 03:16:01 -0700
commit3302281f0028684082be57885a40c063b906008e (patch)
treecbfc2d8ea57d3bf687c7178db37fa5b6367fd092
parent54f07a7ebce933784ed3f5ad3ec6dbdb70fe5ad1 (diff)
CHROMIUM: i965: Implement EGL_KHR_mutable_render_bufferchadv/wip/arc-17.3-i965-mutable-render-buffer-v06
Tested with a low-latency handwriting application on Android Nougat on the Chrome OS Pixelbook (codename Eve) with Kabylake. BUG=b:77899911 TEST=No android-cts-7.1 regressions on Eve. Change-Id: Ia816fa6b0a1158f81e5b63477451bf337c2001aa
-rw-r--r--src/mesa/drivers/dri/i965/brw_context.c86
-rw-r--r--src/mesa/drivers/dri/i965/brw_context.h12
-rw-r--r--src/mesa/drivers/dri/i965/intel_screen.c13
3 files changed, 107 insertions, 4 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index 3085ba40dab..9a6aa2dcdb9 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -236,13 +236,42 @@ intel_flush_front(struct gl_context *ctx)
}
static void
+brw_display_shared_buffer(struct brw_context *brw)
+{
+ __DRIcontext *dri_context = brw->driContext;
+ __DRIdrawable *dri_drawable = dri_context->driDrawablePriv;
+ __DRIscreen *dri_screen = brw->screen->driScrnPriv;
+ int fence_fd = -1;
+
+ if (!brw->is_shared_buffer_bound)
+ return;
+
+ if (!brw->is_shared_buffer_dirty)
+ return;
+
+ if (brw->screen->has_exec_fence) {
+ /* This function is always called during a flush operation, so there is
+ * no need to flush again here. But we want to provide a fence_fd to the
+ * loader, and a redundant flush is the easiest way to acquire one.
+ */
+ if (intel_batchbuffer_flush_fence(brw, -1, &fence_fd))
+ return;
+ }
+
+ dri_screen->mutableRenderBuffer.loader
+ ->displaySharedBuffer(dri_drawable, fence_fd,
+ dri_drawable->loaderPrivate);
+ brw->is_shared_buffer_dirty = false;
+}
+
+static void
intel_glFlush(struct gl_context *ctx)
{
struct brw_context *brw = brw_context(ctx);
intel_batchbuffer_flush(brw);
intel_flush_front(ctx);
-
+ brw_display_shared_buffer(brw);
brw->need_flush_throttle = true;
}
@@ -1410,6 +1439,11 @@ intel_prepare_render(struct brw_context *brw)
*/
if (_mesa_is_front_buffer_drawing(ctx->DrawBuffer))
brw->front_buffer_dirty = true;
+
+ if (brw->is_shared_buffer_bound) {
+ /* Subsequent rendering will probably dirty the shared buffer. */
+ brw->is_shared_buffer_dirty = true;
+ }
}
/**
@@ -1639,8 +1673,12 @@ intel_update_image_buffer(struct brw_context *intel,
else
last_mt = rb->singlesample_mt;
- if (last_mt && last_mt->bo == buffer->bo)
+ if (last_mt && last_mt->bo == buffer->bo) {
+ if (buffer_type == __DRI_IMAGE_BUFFER_SHARED) {
+ intel_miptree_make_shareable(intel, last_mt);
+ }
return;
+ }
struct intel_mipmap_tree *mt =
intel_miptree_create_for_dri_image(intel, buffer, GL_TEXTURE_2D,
@@ -1660,6 +1698,35 @@ intel_update_image_buffer(struct brw_context *intel,
rb->Base.Base.NumSamples > 1) {
intel_renderbuffer_upsample(intel, rb);
}
+
+ if (buffer_type == __DRI_IMAGE_BUFFER_SHARED) {
+ /* The compositor and the application may access this image
+ * concurrently. The display hardware may even scanout the image while
+ * the GPU is rendering to it. Aux surfaces cause difficulty with
+ * concurrent access, so permanently disable aux for this miptree.
+ *
+ * Perhaps we could improve overall application performance by
+ * re-enabling the aux surface when EGL_RENDER_BUFFER transitions to
+ * EGL_BACK_BUFFER, then disabling it again when EGL_RENDER_BUFFER
+ * returns to EGL_SINGLE_BUFFER. I expect the wins and losses with this
+ * approach to be highly dependent on the application's GL usage.
+ *
+ * I [chadv] expect clever disabling/reenabling to be counterproductive
+ * in the use cases I care about: applications that render nearly
+ * realtime handwriting to the surface while possibly undergiong
+ * simultaneously scanout as a display plane. The app requires low
+ * render latency. Even though the app spends most of its time in
+ * shared-buffer mode, it also frequently transitions between
+ * shared-buffer (EGL_SINGLE_BUFFER) and double-buffer (EGL_BACK_BUFFER)
+ * mode. Visual sutter during the transitions should be avoided.
+ *
+ * In this case, I [chadv] believe reducing the GPU workload at
+ * shared-buffer/double-buffer transitions would offer a smoother app
+ * experience than any savings due to aux compression. But I've
+ * collected no data to prove my theory.
+ */
+ intel_miptree_make_shareable(intel, mt);
+ }
}
static void
@@ -1720,4 +1787,19 @@ intel_update_image_buffers(struct brw_context *brw, __DRIdrawable *drawable)
images.back,
__DRI_IMAGE_BUFFER_BACK);
}
+
+ if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) {
+ assert(images.image_mask == __DRI_IMAGE_BUFFER_SHARED);
+ drawable->w = images.back->width;
+ drawable->h = images.back->height;
+ intel_update_image_buffer(brw,
+ drawable,
+ back_rb,
+ images.back,
+ __DRI_IMAGE_BUFFER_SHARED);
+ brw->is_shared_buffer_bound = true;
+ } else {
+ brw->is_shared_buffer_bound = false;
+ brw->is_shared_buffer_dirty = false;
+ }
}
diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index 26e71e62b54..19b801dae94 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -711,6 +711,18 @@ struct brw_context
*/
bool front_buffer_dirty;
+ /**
+ * True if the __DRIdrawable's current __DRIimageBufferMask is
+ * __DRI_IMAGE_BUFFER_SHARED.
+ */
+ bool is_shared_buffer_bound;
+
+ /**
+ * True if a shared buffer is bound and it has received any rendering since
+ * the previous __DRImutableRenderBufferLoaderExtension::displaySharedBuffer().
+ */
+ bool is_shared_buffer_dirty;
+
/** Framerate throttling: @{ */
struct brw_bo *throttle_batch[2];
diff --git a/src/mesa/drivers/dri/i965/intel_screen.c b/src/mesa/drivers/dri/i965/intel_screen.c
index 6a27745b9ba..b46f380b4aa 100644
--- a/src/mesa/drivers/dri/i965/intel_screen.c
+++ b/src/mesa/drivers/dri/i965/intel_screen.c
@@ -1423,12 +1423,17 @@ static const __DRIrobustnessExtension dri2Robustness = {
.base = { __DRI2_ROBUSTNESS, 1 }
};
+static const __DRImutableRenderBufferDriverExtension intelMutableRenderBufferExtension = {
+ .base = { __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1 },
+};
+
static const __DRIextension *screenExtensions[] = {
&intelTexBufferExtension.base,
&intelFenceExtension.base,
&intelFlushExtension.base,
&intelImageExtension.base,
&intelRendererQueryExtension.base,
+ &intelMutableRenderBufferExtension.base,
&dri2ConfigQueryExtension.base,
&dri2NoErrorExtension.base,
NULL
@@ -1440,6 +1445,7 @@ static const __DRIextension *intelRobustScreenExtensions[] = {
&intelFlushExtension.base,
&intelImageExtension.base,
&intelRendererQueryExtension.base,
+ &intelMutableRenderBufferExtension.base,
&dri2ConfigQueryExtension.base,
&dri2Robustness.base,
&dri2NoErrorExtension.base,
@@ -1952,7 +1958,9 @@ intel_screen_make_configs(__DRIscreen *dri_screen)
else
num_formats = 3;
- /* Generate singlesample configs without accumulation buffer. */
+ /* Generate singlesample configs, each without accumulation buffer
+ * and with EGL_MUTABLE_RENDER_BUFFER_BIT_KHR.
+ */
for (unsigned i = 0; i < num_formats; i++) {
__DRIconfig **new_configs;
int num_depth_stencil_bits = 2;
@@ -1983,7 +1991,8 @@ intel_screen_make_configs(__DRIscreen *dri_screen)
num_depth_stencil_bits,
back_buffer_modes, 2,
singlesample_samples, 1,
- false, false, false);
+ false, false,
+ /*mutable_render_buffer*/ true);
configs = driConcatConfigs(configs, new_configs);
}