From 79653c12d6da4d89aaa73e4e8260a84d91f93593 Mon Sep 17 00:00:00 2001 From: Chad Versace Date: Tue, 15 Nov 2011 07:08:49 -0800 Subject: intel: Fix separate stencil in builtin DRI2 backend intelAllocateBuffer() was oblivious to separate stencil buffers. This patch fixes it to allocate a non-tiled stencil buffer with special pitch, just as the DDX does. Without this, any app that attempted to create an EGL surface with stencil bits would crash. Of course, this affected only environments that used the builtin DRI2 backend, such as Android and Wayland. Fixes GLBenchmark2.1 on Android on gen7. Note: This is a candidate for the 7.11 branch. Tested-by: Louie Tsaie Signed-off-by: Chad Versace --- src/mesa/drivers/dri/intel/intel_screen.c | 89 +++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 9 deletions(-) (limited to 'src/mesa') diff --git a/src/mesa/drivers/dri/intel/intel_screen.c b/src/mesa/drivers/dri/intel/intel_screen.c index ae55700dace..5a73030660f 100644 --- a/src/mesa/drivers/dri/intel/intel_screen.c +++ b/src/mesa/drivers/dri/intel/intel_screen.c @@ -796,6 +796,54 @@ struct intel_buffer { struct intel_region *region; }; +/** + * \brief Get tiling format for a DRI buffer. + * + * \param attachment is the buffer's attachmet point, such as + * __DRI_BUFFER_DEPTH. + * \param out_tiling is the returned tiling format for buffer. + * \return false if attachment is unrecognized or is incompatible with screen. + */ +static bool +intel_get_dri_buffer_tiling(struct intel_screen *screen, + uint32_t attachment, + uint32_t *out_tiling) +{ + if (screen->gen < 4) { + *out_tiling = I915_TILING_X; + return true; + } + + switch (attachment) { + case __DRI_BUFFER_DEPTH: + case __DRI_BUFFER_DEPTH_STENCIL: + case __DRI_BUFFER_HIZ: + *out_tiling = I915_TILING_Y; + return true; + case __DRI_BUFFER_ACCUM: + case __DRI_BUFFER_FRONT_LEFT: + case __DRI_BUFFER_FRONT_RIGHT: + case __DRI_BUFFER_BACK_LEFT: + case __DRI_BUFFER_BACK_RIGHT: + case __DRI_BUFFER_FAKE_FRONT_LEFT: + case __DRI_BUFFER_FAKE_FRONT_RIGHT: + *out_tiling = I915_TILING_X; + return true; + case __DRI_BUFFER_STENCIL: + /* The stencil buffer is W tiled. However, we request from the kernel + * a non-tiled buffer because the GTT is incapable of W fencing. + */ + *out_tiling = I915_TILING_NONE; + return true; + default: + if(unlikely(INTEL_DEBUG & DEBUG_DRI)) { + fprintf(stderr, "error: %s: unrecognized DRI buffer attachment 0x%x\n", + __FUNCTION__, attachment); + } + return false; + } +} + static __DRIbuffer * intelAllocateBuffer(__DRIscreen *screen, unsigned attachment, unsigned format, @@ -803,22 +851,45 @@ intelAllocateBuffer(__DRIscreen *screen, { struct intel_buffer *intelBuffer; struct intel_screen *intelScreen = screen->driverPrivate; + uint32_t tiling; + uint32_t region_width; + uint32_t region_height; + uint32_t region_cpp; + + bool ok = true; + + ok = intel_get_dri_buffer_tiling(intelScreen, attachment, &tiling); + if (!ok) + return NULL; intelBuffer = CALLOC(sizeof *intelBuffer); if (intelBuffer == NULL) return NULL; - if ((attachment == __DRI_BUFFER_DEPTH || - attachment == __DRI_BUFFER_STENCIL || - attachment == __DRI_BUFFER_DEPTH_STENCIL) && - intelScreen->gen >= 4) - tiling = I915_TILING_Y; - else - tiling = I915_TILING_X; + if (attachment == __DRI_BUFFER_STENCIL) { + /* The stencil buffer has quirky pitch requirements. From Vol 2a, + * 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface Pitch": + * The pitch must be set to 2x the value computed based on width, as + * the stencil buffer is stored with two rows interleaved. + * To accomplish this, we resort to the nasty hack of doubling the + * region's cpp and halving its height. + */ + region_width = ALIGN(width, 64); + region_height = ALIGN(ALIGN(height, 2) / 2, 64); + region_cpp = format / 4; + } else { + region_width = width; + region_height = height; + region_cpp = format / 8; + } - intelBuffer->region = intel_region_alloc(intelScreen, tiling, - format / 8, width, height, true); + intelBuffer->region = intel_region_alloc(intelScreen, + tiling, + region_cpp, + region_width, + region_height, + true); if (intelBuffer->region == NULL) { FREE(intelBuffer); -- cgit v1.2.3