#include "main/framebuffer.h"
#include "main/imports.h"
#include "main/points.h"
+#include "main/renderbuffer.h"
#include "swrast/swrast.h"
#include "swrast_setup/swrast_setup.h"
#include "intel_fbo.h"
#include "intel_bufmgr.h"
#include "intel_screen.h"
+#include "intel_mipmap_tree.h"
-#include "drirenderbuffer.h"
#include "utils.h"
-
+#include "../glsl/ralloc.h"
#ifndef INTEL_DEBUG
int INTEL_DEBUG = (0);
#endif
-#define DRIVER_DATE "20100330 DEVELOPMENT"
-#define DRIVER_DATE_GEM "GEM " DRIVER_DATE
-
-
static const GLubyte *
intelGetString(struct gl_context * ctx, GLenum name)
{
case PCI_CHIP_SANDYBRIDGE_S:
chipset = "Intel(R) Sandybridge Server";
break;
+ case PCI_CHIP_IVYBRIDGE_GT1:
+ case PCI_CHIP_IVYBRIDGE_GT2:
+ chipset = "Intel(R) Ivybridge Desktop";
+ break;
+ case PCI_CHIP_IVYBRIDGE_M_GT1:
+ case PCI_CHIP_IVYBRIDGE_M_GT2:
+ chipset = "Intel(R) Ivybridge Mobile";
+ break;
+ case PCI_CHIP_IVYBRIDGE_S_GT1:
+ chipset = "Intel(R) Ivybridge Server";
+ break;
default:
chipset = "Unknown Intel Chipset";
break;
}
- (void) driGetRendererString(buffer, chipset, DRIVER_DATE_GEM, 0);
+ (void) driGetRendererString(buffer, chipset, 0);
return (GLubyte *) buffer;
default:
/* We set the dirty bit in intel_prepare_render() if we're
* front buffer rendering once we get there.
*/
- intel->front_buffer_dirty = GL_FALSE;
+ intel->front_buffer_dirty = false;
}
}
}
return _mesa_get_format_bytes(rb->Base.Format) * 8;
}
+static void
+intel_query_dri2_buffers_no_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer **buffers,
+ int *count);
+
+static void
+intel_process_dri2_buffer_no_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer *buffer,
+ struct intel_renderbuffer *rb,
+ const char *buffer_name);
+
+static void
+intel_query_dri2_buffers_with_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer **buffers,
+ unsigned **attachments,
+ int *count);
+
+static void
+intel_process_dri2_buffer_with_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer *buffer,
+ struct intel_renderbuffer *rb,
+ const char *buffer_name);
+static void
+intel_verify_dri2_has_hiz(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer **buffers,
+ unsigned **attachments,
+ int *count);
+
void
intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
{
struct gl_framebuffer *fb = drawable->driverPrivate;
struct intel_renderbuffer *rb;
- struct intel_region *region, *depth_region;
struct intel_context *intel = context->driverPrivate;
- struct intel_renderbuffer *front_rb, *back_rb, *depth_rb, *stencil_rb;
__DRIbuffer *buffers = NULL;
- __DRIscreen *screen;
+ unsigned *attachments = NULL;
int i, count;
- unsigned int attachments[10];
const char *region_name;
+ bool try_separate_stencil =
+ intel->has_separate_stencil &&
+ intel->intelScreen->dri2_has_hiz != INTEL_DRI2_HAS_HIZ_FALSE &&
+ intel->intelScreen->driScrnPriv->dri2.loader != NULL &&
+ intel->intelScreen->driScrnPriv->dri2.loader->base.version > 2 &&
+ intel->intelScreen->driScrnPriv->dri2.loader->getBuffersWithFormat != NULL;
+
+ assert(!intel->must_use_separate_stencil || try_separate_stencil);
+
/* If we're rendering to the fake front buffer, make sure all the
* pending drawing has landed on the real front buffer. Otherwise
* when we eventually get to DRI2GetBuffersWithFormat the stale
if (unlikely(INTEL_DEBUG & DEBUG_DRI))
fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable);
- screen = intel->intelScreen->driScrnPriv;
-
- if (screen->dri2.loader
- && (screen->dri2.loader->base.version > 2)
- && (screen->dri2.loader->getBuffersWithFormat != NULL)) {
-
- front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
- back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
- depth_rb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
- stencil_rb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
-
- i = 0;
- if ((intel->is_front_buffer_rendering ||
- intel->is_front_buffer_reading ||
- !back_rb) && front_rb) {
- attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
- attachments[i++] = intel_bits_per_pixel(front_rb);
- }
-
- if (back_rb) {
- attachments[i++] = __DRI_BUFFER_BACK_LEFT;
- attachments[i++] = intel_bits_per_pixel(back_rb);
- }
-
- if ((depth_rb != NULL) && (stencil_rb != NULL)) {
- attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
- attachments[i++] = intel_bits_per_pixel(depth_rb);
- } else if (depth_rb != NULL) {
- attachments[i++] = __DRI_BUFFER_DEPTH;
- attachments[i++] = intel_bits_per_pixel(depth_rb);
- } else if (stencil_rb != NULL) {
- attachments[i++] = __DRI_BUFFER_STENCIL;
- attachments[i++] = intel_bits_per_pixel(stencil_rb);
- }
-
- buffers =
- (*screen->dri2.loader->getBuffersWithFormat)(drawable,
- &drawable->w,
- &drawable->h,
- attachments, i / 2,
- &count,
- drawable->loaderPrivate);
- } else if (screen->dri2.loader) {
- i = 0;
- if (intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT))
- attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
- if (intel_get_renderbuffer(fb, BUFFER_BACK_LEFT))
- attachments[i++] = __DRI_BUFFER_BACK_LEFT;
- if (intel_get_renderbuffer(fb, BUFFER_DEPTH))
- attachments[i++] = __DRI_BUFFER_DEPTH;
- if (intel_get_renderbuffer(fb, BUFFER_STENCIL))
- attachments[i++] = __DRI_BUFFER_STENCIL;
-
- buffers = (*screen->dri2.loader->getBuffers)(drawable,
- &drawable->w,
- &drawable->h,
- attachments, i,
- &count,
- drawable->loaderPrivate);
+ if (try_separate_stencil) {
+ intel_query_dri2_buffers_with_separate_stencil(intel, drawable, &buffers,
+ &attachments, &count);
+ } else {
+ intel_query_dri2_buffers_no_separate_stencil(intel, drawable, &buffers,
+ &count);
}
if (buffers == NULL)
return;
- drawable->x = 0;
- drawable->y = 0;
- drawable->backX = 0;
- drawable->backY = 0;
- drawable->numClipRects = 1;
- drawable->pClipRects[0].x1 = 0;
- drawable->pClipRects[0].y1 = 0;
- drawable->pClipRects[0].x2 = drawable->w;
- drawable->pClipRects[0].y2 = drawable->h;
- drawable->numBackClipRects = 1;
- drawable->pBackClipRects[0].x1 = 0;
- drawable->pBackClipRects[0].y1 = 0;
- drawable->pBackClipRects[0].x2 = drawable->w;
- drawable->pBackClipRects[0].y2 = drawable->h;
-
- depth_region = NULL;
for (i = 0; i < count; i++) {
switch (buffers[i].attachment) {
case __DRI_BUFFER_FRONT_LEFT:
region_name = "dri2 depth buffer";
break;
+ case __DRI_BUFFER_HIZ:
+ /* The hiz region resides in the depth renderbuffer. */
+ rb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ region_name = "dri2 hiz buffer";
+ break;
+
case __DRI_BUFFER_DEPTH_STENCIL:
rb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
region_name = "dri2 depth / stencil buffer";
return;
}
- if (rb == NULL)
- continue;
-
- if (rb->region && rb->region->name == buffers[i].name)
- continue;
-
- if (unlikely(INTEL_DEBUG & DEBUG_DRI))
- fprintf(stderr,
- "attaching buffer %d, at %d, cpp %d, pitch %d\n",
- buffers[i].name, buffers[i].attachment,
- buffers[i].cpp, buffers[i].pitch);
-
- if (buffers[i].attachment == __DRI_BUFFER_STENCIL && depth_region) {
- if (unlikely(INTEL_DEBUG & DEBUG_DRI))
- fprintf(stderr, "(reusing depth buffer as stencil)\n");
- intel_region_reference(®ion, depth_region);
+ if (try_separate_stencil) {
+ intel_process_dri2_buffer_with_separate_stencil(intel, drawable,
+ &buffers[i], rb,
+ region_name);
+ } else {
+ intel_process_dri2_buffer_no_separate_stencil(intel, drawable,
+ &buffers[i], rb,
+ region_name);
}
- else
- region = intel_region_alloc_for_handle(intel->intelScreen,
- buffers[i].cpp,
- drawable->w,
- drawable->h,
- buffers[i].pitch / buffers[i].cpp,
- buffers[i].name,
- region_name);
-
- if (buffers[i].attachment == __DRI_BUFFER_DEPTH)
- depth_region = region;
-
- intel_renderbuffer_set_region(intel, rb, region);
- intel_region_release(®ion);
-
- if (buffers[i].attachment == __DRI_BUFFER_DEPTH_STENCIL) {
- rb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
- if (rb != NULL) {
- struct intel_region *stencil_region = NULL;
-
- if (rb->region && rb->region->name == buffers[i].name)
- continue;
+ }
- intel_region_reference(&stencil_region, region);
- intel_renderbuffer_set_region(intel, rb, stencil_region);
- intel_region_release(&stencil_region);
- }
- }
+ if (try_separate_stencil
+ && intel->intelScreen->dri2_has_hiz == INTEL_DRI2_HAS_HIZ_UNKNOWN) {
+ intel_verify_dri2_has_hiz(intel, drawable, &buffers, &attachments,
+ &count);
}
+ if (attachments)
+ free(attachments);
+
driUpdateFramebufferSize(&intel->ctx, drawable);
}
if (drawable && drawable->dri2.stamp != driContext->dri2.draw_stamp) {
if (drawable->lastStamp != drawable->dri2.stamp)
intel_update_renderbuffers(driContext, drawable);
- intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
+ intel_draw_buffer(&intel->ctx);
driContext->dri2.draw_stamp = drawable->dri2.stamp;
}
* mark it as dirty here.
*/
if (intel->is_front_buffer_rendering)
- intel->front_buffer_dirty = GL_TRUE;
+ intel->front_buffer_dirty = true;
/* Wait for the swapbuffers before the one we just emitted, so we
* don't get too many swaps outstanding for apps that are GPU-heavy
drm_intel_bo_wait_rendering(intel->first_post_swapbuffers_batch);
drm_intel_bo_unreference(intel->first_post_swapbuffers_batch);
intel->first_post_swapbuffers_batch = NULL;
- intel->need_throttle = GL_FALSE;
+ intel->need_throttle = false;
}
}
if (intel->saved_viewport)
intel->saved_viewport(ctx, x, y, w, h);
- if (!intel->meta.internal_viewport_call && ctx->DrawBuffer->Name == 0) {
+ if (ctx->DrawBuffer->Name == 0) {
dri2InvalidateDrawable(driContext->driDrawablePriv);
dri2InvalidateDrawable(driContext->driReadablePriv);
}
{ "sleep", DEBUG_SLEEP },
{ "stats", DEBUG_STATS },
{ "tile", DEBUG_TILE },
- { "sing", DEBUG_SINGLE_THREAD },
- { "thre", DEBUG_SINGLE_THREAD },
{ "wm", DEBUG_WM },
{ "urb", DEBUG_URB },
{ "vs", DEBUG_VS },
struct intel_context *intel = intel_context(ctx);
_swrast_InvalidateState(ctx, new_state);
- _swsetup_InvalidateState(ctx, new_state);
_vbo_InvalidateState(ctx, new_state);
- _tnl_InvalidateState(ctx, new_state);
- _tnl_invalidate_vertex_state(ctx, new_state);
intel->NewGLState |= new_state;
}
void
-intel_flush(struct gl_context *ctx)
+intel_flush_rendering_to_batch(struct gl_context *ctx)
{
struct intel_context *intel = intel_context(ctx);
if (intel->gen < 4)
INTEL_FIREVERTICES(intel);
+}
- if (intel->batch->map != intel->batch->ptr)
- intel_batchbuffer_flush(intel->batch);
+void
+intel_flush(struct gl_context *ctx)
+{
+ struct intel_context *intel = intel_context(ctx);
+
+ intel_flush_rendering_to_batch(ctx);
+
+ if (intel->batch.used)
+ intel_batchbuffer_flush(intel);
}
static void
intel_flush(ctx);
intel_flush_front(ctx);
- intel->need_throttle = GL_TRUE;
+ if (intel->is_front_buffer_rendering)
+ intel->need_throttle = true;
}
void
intelFinish(struct gl_context * ctx)
{
- struct gl_framebuffer *fb = ctx->DrawBuffer;
- int i;
+ struct intel_context *intel = intel_context(ctx);
intel_flush(ctx);
intel_flush_front(ctx);
- for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
- struct intel_renderbuffer *irb;
-
- irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]);
-
- if (irb && irb->region)
- drm_intel_bo_wait_rendering(irb->region->buffer);
- }
- if (fb->_DepthBuffer) {
- /* XXX: Wait on buffer idle */
- }
+ if (intel->batch.last_bo)
+ drm_intel_bo_wait_rendering(intel->batch.last_bo);
}
void
intel_init_syncobj_functions(functions);
}
-
-GLboolean
+bool
intelInitContext(struct intel_context *intel,
int api,
const struct gl_config * mesaVis,
struct gl_context *ctx = &intel->ctx;
struct gl_context *shareCtx = (struct gl_context *) sharedContextPrivate;
__DRIscreen *sPriv = driContextPriv->driScreenPriv;
- struct intel_screen *intelScreen = sPriv->private;
+ struct intel_screen *intelScreen = sPriv->driverPrivate;
int bo_reuse_mode;
struct gl_config visual;
/* we can't do anything without a connection to the device */
if (intelScreen->bufmgr == NULL)
- return GL_FALSE;
+ return false;
/* Can't rely on invalidate events, fall back to glViewport hack */
if (!driContextPriv->driScreenPriv->dri2.useInvalidate) {
mesaVis = &visual;
}
- if (!_mesa_initialize_context_for_api(&intel->ctx, api, mesaVis, shareCtx,
- functions, (void *) intel)) {
+ if (!_mesa_initialize_context(&intel->ctx, api, mesaVis, shareCtx,
+ functions, (void *) intel)) {
printf("%s: failed to init mesa context\n", __FUNCTION__);
- return GL_FALSE;
+ return false;
}
driContextPriv->driverPrivate = intel;
intel->driContext = driContextPriv;
intel->driFd = sPriv->fd;
- intel->has_xrgb_textures = GL_TRUE;
- if (IS_GEN6(intel->intelScreen->deviceID)) {
- intel->gen = 6;
- intel->needs_ff_sync = GL_TRUE;
- intel->has_luminance_srgb = GL_TRUE;
- } else if (IS_GEN5(intel->intelScreen->deviceID)) {
- intel->gen = 5;
- intel->needs_ff_sync = GL_TRUE;
- intel->has_luminance_srgb = GL_TRUE;
- } else if (IS_965(intel->intelScreen->deviceID)) {
- intel->gen = 4;
- if (IS_G4X(intel->intelScreen->deviceID)) {
- intel->has_luminance_srgb = GL_TRUE;
- intel->is_g4x = GL_TRUE;
- }
- } else if (IS_9XX(intel->intelScreen->deviceID)) {
- intel->gen = 3;
- if (IS_945(intel->intelScreen->deviceID)) {
- intel->is_945 = GL_TRUE;
- }
- } else {
- intel->gen = 2;
- if (intel->intelScreen->deviceID == PCI_CHIP_I830_M ||
- intel->intelScreen->deviceID == PCI_CHIP_845_G) {
- intel->has_xrgb_textures = GL_FALSE;
- }
+ intel->gen = intelScreen->gen;
+
+ const int devID = intelScreen->deviceID;
+
+ if (IS_SNB_GT1(devID) || IS_IVB_GT1(devID))
+ intel->gt = 1;
+ else if (IS_SNB_GT2(devID) || IS_IVB_GT2(devID))
+ intel->gt = 2;
+ else
+ intel->gt = 0;
+
+ if (IS_G4X(devID)) {
+ intel->is_g4x = true;
+ } else if (IS_945(devID)) {
+ intel->is_945 = true;
+ }
+
+ if (intel->gen >= 5) {
+ intel->needs_ff_sync = true;
}
+ intel->has_separate_stencil = intel->intelScreen->hw_has_separate_stencil;
+ intel->must_use_separate_stencil = intel->intelScreen->hw_must_use_separate_stencil;
+ intel->has_hiz = intel->intelScreen->hw_has_hiz;
+
+ memset(&ctx->TextureFormatSupported, 0,
+ sizeof(ctx->TextureFormatSupported));
+ ctx->TextureFormatSupported[MESA_FORMAT_ARGB8888] = true;
+ if (devID != PCI_CHIP_I830_M && devID != PCI_CHIP_845_G)
+ ctx->TextureFormatSupported[MESA_FORMAT_XRGB8888] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_ARGB4444] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_ARGB1555] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_RGB565] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_L8] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_A8] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_I8] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_AL88] = true;
+
+ /* Depth and stencil */
+ ctx->TextureFormatSupported[MESA_FORMAT_S8_Z24] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_X8_Z24] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_S8] = intel->has_separate_stencil;
+
+ /*
+ * This was disabled in initial FBO enabling to avoid combinations
+ * of depth+stencil that wouldn't work together. We since decided
+ * that it was OK, since it's up to the app to come up with the
+ * combo that actually works, so this can probably be re-enabled.
+ */
+ /*
+ ctx->TextureFormatSupported[MESA_FORMAT_Z16] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_Z24] = true;
+ */
+
+ /* ctx->Extensions.MESA_ycbcr_texture */
+ ctx->TextureFormatSupported[MESA_FORMAT_YCBCR] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_YCBCR_REV] = true;
+
+ /* GL_3DFX_texture_compression_FXT1 */
+ ctx->TextureFormatSupported[MESA_FORMAT_RGB_FXT1] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_RGBA_FXT1] = true;
+
+ /* GL_EXT_texture_compression_s3tc */
+ ctx->TextureFormatSupported[MESA_FORMAT_RGB_DXT1] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_RGBA_DXT1] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_RGBA_DXT3] = true;
+ ctx->TextureFormatSupported[MESA_FORMAT_RGBA_DXT5] = true;
+
driParseConfigFiles(&intel->optionCache, &intelScreen->optionCache,
sPriv->myNum, (intel->gen >= 4) ? "i965" : "i915");
- if (intelScreen->deviceID == PCI_CHIP_I865_G)
+ if (intel->gen < 4)
intel->maxBatchSize = 4096;
else
- intel->maxBatchSize = BATCH_SZ;
+ intel->maxBatchSize = sizeof(intel->batch.map);
intel->bufmgr = intelScreen->bufmgr;
ctx->Const.MaxSamples = 1.0;
+ if (intel->gen >= 6)
+ ctx->Const.MaxClipPlanes = 8;
+
+ ctx->Const.StripTextureBorder = GL_TRUE;
+
/* reinitialize the context point state.
* It depend on constants in __struct gl_contextRec::Const
*/
_mesa_init_point(ctx);
- meta_init_metaops(ctx, &intel->meta);
if (intel->gen >= 4) {
+ ctx->Const.sRGBCapable = true;
if (MAX_WIDTH > 8192)
ctx->Const.MaxRenderbufferSize = 8192;
} else {
_swsetup_CreateContext(ctx);
/* Configure swrast to match hardware characteristics: */
- _swrast_allow_pixel_fog(ctx, GL_FALSE);
- _swrast_allow_vertex_fog(ctx, GL_TRUE);
+ _swrast_allow_pixel_fog(ctx, false);
+ _swrast_allow_vertex_fog(ctx, true);
_mesa_meta_init(ctx);
intelInitExtensions(ctx);
break;
case API_OPENGLES:
+ intelInitExtensionsES1(ctx);
break;
case API_OPENGLES2:
intelInitExtensionsES2(ctx);
INTEL_DEBUG = driParseDebugString(getenv("INTEL_DEBUG"), debug_control);
if (INTEL_DEBUG & DEBUG_BUFMGR)
- dri_bufmgr_set_debug(intel->bufmgr, GL_TRUE);
+ dri_bufmgr_set_debug(intel->bufmgr, true);
- intel->batch = intel_batchbuffer_alloc(intel);
+ intel_batchbuffer_init(intel);
intel_fbo_init(intel);
- if (intel->ctx.Mesa_DXTn) {
- _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc");
- _mesa_enable_extension(ctx, "GL_S3_s3tc");
- }
- else if (driQueryOptionb(&intel->optionCache, "force_s3tc_enable")) {
- _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc");
- }
intel->use_texture_tiling = driQueryOptionb(&intel->optionCache,
"texture_tiling");
intel->use_early_z = driQueryOptionb(&intel->optionCache, "early_z");
intel->always_flush_cache = 1;
}
- return GL_TRUE;
+ return true;
}
void
_mesa_meta_free(&intel->ctx);
- meta_destroy_metaops(&intel->meta);
-
intel->vtbl.destroy(intel);
_swsetup_DestroyContext(&intel->ctx);
_swrast_DestroyContext(&intel->ctx);
intel->Fallback = 0x0; /* don't call _swrast_Flush later */
- intel_batchbuffer_free(intel->batch);
- intel->batch = NULL;
+ intel_batchbuffer_free(intel);
free(intel->prim.vb);
intel->prim.vb = NULL;
/* free the Mesa context */
_mesa_free_context_data(&intel->ctx);
- FREE(intel);
+ _math_matrix_dtr(&intel->ViewportMatrix);
+
+ ralloc_free(intel);
driContextPriv->driverPrivate = NULL;
}
}
/* Unset current context and dispath table */
_mesa_make_current(NULL, NULL, NULL);
- return GL_TRUE;
+ return true;
}
GLboolean
* is NULL at that point. We can't call _mesa_makecurrent()
* first, since we need the buffer size for the initial
* viewport. So just call intel_draw_buffer() again here. */
- intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
+ intel_draw_buffer(&intel->ctx);
}
else {
_mesa_make_current(NULL, NULL, NULL);
}
- return GL_TRUE;
+ return true;
+}
+
+/**
+ * \brief Query DRI2 to obtain a DRIdrawable's buffers.
+ *
+ * To determine which DRI buffers to request, examine the renderbuffers
+ * attached to the drawable's framebuffer. Then request the buffers with
+ * DRI2GetBuffers() or DRI2GetBuffersWithFormat().
+ *
+ * This is called from intel_update_renderbuffers(). It is used only if either
+ * the hardware or the X driver lacks separate stencil support.
+ *
+ * \param drawable Drawable whose buffers are queried.
+ * \param buffers [out] List of buffers returned by DRI2 query.
+ * \param buffer_count [out] Number of buffers returned.
+ *
+ * \see intel_update_renderbuffers()
+ * \see DRI2GetBuffers()
+ * \see DRI2GetBuffersWithFormat()
+ */
+static void
+intel_query_dri2_buffers_no_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer **buffers,
+ int *buffer_count)
+{
+ assert(!intel->must_use_separate_stencil);
+
+ __DRIscreen *screen = intel->intelScreen->driScrnPriv;
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+
+ if (screen->dri2.loader
+ && screen->dri2.loader->base.version > 2
+ && screen->dri2.loader->getBuffersWithFormat != NULL) {
+
+ int i = 0;
+ const int max_attachments = 4;
+ unsigned *attachments = calloc(2 * max_attachments, sizeof(unsigned));
+
+ struct intel_renderbuffer *front_rb;
+ struct intel_renderbuffer *back_rb;
+ struct intel_renderbuffer *depth_rb;
+ struct intel_renderbuffer *stencil_rb;
+
+ front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
+ back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
+ depth_rb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ stencil_rb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
+
+ if ((intel->is_front_buffer_rendering ||
+ intel->is_front_buffer_reading ||
+ !back_rb) && front_rb) {
+ attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
+ attachments[i++] = intel_bits_per_pixel(front_rb);
+ }
+
+ if (back_rb) {
+ attachments[i++] = __DRI_BUFFER_BACK_LEFT;
+ attachments[i++] = intel_bits_per_pixel(back_rb);
+ }
+
+ if (depth_rb && stencil_rb) {
+ attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
+ attachments[i++] = intel_bits_per_pixel(depth_rb);
+ } else if (depth_rb) {
+ attachments[i++] = __DRI_BUFFER_DEPTH;
+ attachments[i++] = intel_bits_per_pixel(depth_rb);
+ } else if (stencil_rb) {
+ attachments[i++] = __DRI_BUFFER_STENCIL;
+ attachments[i++] = intel_bits_per_pixel(stencil_rb);
+ }
+
+ assert(i <= 2 * max_attachments);
+
+ *buffers = screen->dri2.loader->getBuffersWithFormat(drawable,
+ &drawable->w,
+ &drawable->h,
+ attachments, i / 2,
+ buffer_count,
+ drawable->loaderPrivate);
+ free(attachments);
+
+ } else if (screen->dri2.loader) {
+
+ int i = 0;
+ const int max_attachments = 4;
+ unsigned *attachments = calloc(max_attachments, sizeof(unsigned));
+
+ if (intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT))
+ attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
+ if (intel_get_renderbuffer(fb, BUFFER_BACK_LEFT))
+ attachments[i++] = __DRI_BUFFER_BACK_LEFT;
+ if (intel_get_renderbuffer(fb, BUFFER_DEPTH))
+ attachments[i++] = __DRI_BUFFER_DEPTH;
+ if (intel_get_renderbuffer(fb, BUFFER_STENCIL))
+ attachments[i++] = __DRI_BUFFER_STENCIL;
+
+ assert(i <= max_attachments);
+
+ *buffers = screen->dri2.loader->getBuffersWithFormat(drawable,
+ &drawable->w,
+ &drawable->h,
+ attachments, i,
+ buffer_count,
+ drawable->loaderPrivate);
+ free(attachments);
+
+ } else {
+ *buffers = NULL;
+ *buffer_count = 0;
+ }
+}
+
+/**
+ * \brief Assign a DRI buffer's DRM region to a renderbuffer.
+ *
+ * This is called from intel_update_renderbuffers(). It is used only if
+ * either the hardware or the X driver lacks separate stencil support.
+ *
+ * \par Note:
+ * DRI buffers whose attachment point is DRI2BufferStencil or
+ * DRI2BufferDepthStencil are handled as special cases.
+ *
+ * \param buffer_name is a human readable name, such as "dri2 front buffer",
+ * that is passed to intel_region_alloc_for_handle().
+ *
+ * \see intel_update_renderbuffers()
+ * \see intel_region_alloc_for_handle()
+ */
+static void
+intel_process_dri2_buffer_no_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer *buffer,
+ struct intel_renderbuffer *rb,
+ const char *buffer_name)
+{
+ assert(!intel->must_use_separate_stencil);
+
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+ struct intel_renderbuffer *depth_rb = NULL;
+
+ if (!rb)
+ return;
+
+ if (rb->mt &&
+ rb->mt->region &&
+ rb->mt->region->name == buffer->name)
+ return;
+
+ if (unlikely(INTEL_DEBUG & DEBUG_DRI)) {
+ fprintf(stderr,
+ "attaching buffer %d, at %d, cpp %d, pitch %d\n",
+ buffer->name, buffer->attachment,
+ buffer->cpp, buffer->pitch);
+ }
+
+ bool identify_depth_and_stencil = false;
+ if (buffer->attachment == __DRI_BUFFER_STENCIL) {
+ struct intel_renderbuffer *depth_rb =
+ intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ identify_depth_and_stencil = depth_rb && depth_rb->mt;
+ }
+
+ if (identify_depth_and_stencil) {
+ if (unlikely(INTEL_DEBUG & DEBUG_DRI)) {
+ fprintf(stderr, "(reusing depth buffer as stencil)\n");
+ }
+ intel_miptree_reference(&rb->mt, depth_rb->mt);
+ } else {
+ intel_miptree_release(&rb->mt);
+ struct intel_region *region =
+ intel_region_alloc_for_handle(intel->intelScreen,
+ buffer->cpp,
+ drawable->w,
+ drawable->h,
+ buffer->pitch / buffer->cpp,
+ buffer->name,
+ buffer_name);
+ if (!region)
+ return;
+
+ rb->mt = intel_miptree_create_for_region(intel,
+ GL_TEXTURE_2D,
+ rb->Base.Format,
+ region);
+ intel_region_release(®ion);
+ if (!rb->mt)
+ return;
+ }
+
+ if (buffer->attachment == __DRI_BUFFER_DEPTH_STENCIL) {
+ struct intel_renderbuffer *stencil_rb =
+ intel_get_renderbuffer(fb, BUFFER_STENCIL);
+
+ if (!stencil_rb)
+ return;
+
+ /* The rb passed in is the BUFFER_DEPTH attachment, and we need
+ * to associate this region to BUFFER_STENCIL as well.
+ */
+ intel_miptree_reference(&stencil_rb->mt, rb->mt);
+ }
+}
+
+/**
+ * \brief Query DRI2 to obtain a DRIdrawable's buffers.
+ *
+ * To determine which DRI buffers to request, examine the renderbuffers
+ * attached to the drawable's framebuffer. Then request the buffers with
+ * DRI2GetBuffersWithFormat().
+ *
+ * This is called from intel_update_renderbuffers(). It is used when 1) the
+ * hardware supports separate stencil and 2) the X driver's separate stencil
+ * support has been verified to work or is still unknown.
+ *
+ * \param drawable Drawable whose buffers are queried.
+ * \param buffers [out] List of buffers returned by DRI2 query.
+ * \param buffer_count [out] Number of buffers returned.
+ * \param attachments [out] List of pairs (attachment_point, bits_per_pixel)
+ * that were submitted in the DRI2 query. Number of pairs
+ * is same as buffer_count.
+ *
+ * \see intel_update_renderbuffers()
+ * \see DRI2GetBuffersWithFormat()
+ * \see enum intel_dri2_has_hiz
+ */
+static void
+intel_query_dri2_buffers_with_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer **buffers,
+ unsigned **attachments,
+ int *count)
+{
+ assert(intel->has_separate_stencil);
+
+ __DRIscreen *screen = intel->intelScreen->driScrnPriv;
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+
+ const int max_attachments = 5;
+ int i = 0;
+
+ *attachments = calloc(2 * max_attachments, sizeof(unsigned));
+ if (!*attachments) {
+ *buffers = NULL;
+ *count = 0;
+ return;
+ }
+
+ struct intel_renderbuffer *front_rb;
+ struct intel_renderbuffer *back_rb;
+ struct intel_renderbuffer *depth_rb;
+ struct intel_renderbuffer *stencil_rb;
+
+ front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
+ back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
+ depth_rb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ stencil_rb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
+
+ if ((intel->is_front_buffer_rendering ||
+ intel->is_front_buffer_reading ||
+ !back_rb) && front_rb) {
+ (*attachments)[i++] = __DRI_BUFFER_FRONT_LEFT;
+ (*attachments)[i++] = intel_bits_per_pixel(front_rb);
+ }
+
+ if (back_rb) {
+ (*attachments)[i++] = __DRI_BUFFER_BACK_LEFT;
+ (*attachments)[i++] = intel_bits_per_pixel(back_rb);
+ }
+
+ /*
+ * We request a separate stencil buffer, and perhaps a hiz buffer too, even
+ * if we do not yet know if the X driver supports it. See the comments for
+ * 'enum intel_dri2_has_hiz'.
+ */
+
+ if (depth_rb) {
+ (*attachments)[i++] = __DRI_BUFFER_DEPTH;
+ (*attachments)[i++] = intel_bits_per_pixel(depth_rb);
+
+ if (intel->vtbl.is_hiz_depth_format(intel, depth_rb->Base.Format)) {
+ /* Depth and hiz buffer have same bpp. */
+ (*attachments)[i++] = __DRI_BUFFER_HIZ;
+ (*attachments)[i++] = intel_bits_per_pixel(depth_rb);
+ }
+ }
+
+ if (stencil_rb) {
+ assert(stencil_rb->Base.Format == MESA_FORMAT_S8);
+ (*attachments)[i++] = __DRI_BUFFER_STENCIL;
+ (*attachments)[i++] = intel_bits_per_pixel(stencil_rb);
+ }
+
+ assert(i <= 2 * max_attachments);
+
+ *buffers = screen->dri2.loader->getBuffersWithFormat(drawable,
+ &drawable->w,
+ &drawable->h,
+ *attachments, i / 2,
+ count,
+ drawable->loaderPrivate);
+
+ if (!*buffers) {
+ free(*attachments);
+ *attachments = NULL;
+ *count = 0;
+ }
+}
+
+/**
+ * \brief Assign a DRI buffer's DRM region to a renderbuffer.
+ *
+ * This is called from intel_update_renderbuffers(). It is used when 1) the
+ * hardware supports separate stencil and 2) the X driver's separate stencil
+ * support has been verified to work or is still unknown.
+ *
+ * \par Note:
+ * DRI buffers whose attachment point is DRI2BufferStencil or DRI2BufferHiz
+ * are handled as special cases.
+ *
+ * \param buffer_name is a human readable name, such as "dri2 front buffer",
+ * that is passed to intel_region_alloc_for_handle().
+ *
+ * \see intel_update_renderbuffers()
+ * \see intel_region_alloc_for_handle()
+ * \see enum intel_dri2_has_hiz
+ */
+static void
+intel_process_dri2_buffer_with_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer *buffer,
+ struct intel_renderbuffer *rb,
+ const char *buffer_name)
+{
+ assert(intel->has_separate_stencil);
+ assert(buffer->attachment != __DRI_BUFFER_DEPTH_STENCIL);
+
+ if (!rb)
+ return;
+
+ /* If the renderbuffer's and DRIbuffer's regions match, then continue. */
+ if ((buffer->attachment != __DRI_BUFFER_HIZ &&
+ rb->mt &&
+ rb->mt->region &&
+ rb->mt->region->name == buffer->name) ||
+ (buffer->attachment == __DRI_BUFFER_HIZ &&
+ rb->mt &&
+ rb->mt->hiz_mt &&
+ rb->mt->hiz_mt->region->name == buffer->name)) {
+ return;
+ }
+
+ if (unlikely(INTEL_DEBUG & DEBUG_DRI)) {
+ fprintf(stderr,
+ "attaching buffer %d, at %d, cpp %d, pitch %d\n",
+ buffer->name, buffer->attachment,
+ buffer->cpp, buffer->pitch);
+ }
+
+ int buffer_width;
+ int buffer_height;
+ if (buffer->attachment == __DRI_BUFFER_STENCIL) {
+ /* The stencil buffer has quirky pitch requirements. From Section
+ * 2.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 satisfy the pitch requirement, the X driver allocated the region
+ * with the following dimensions.
+ */
+ buffer_width = ALIGN(drawable->w, 64);
+ buffer_height = ALIGN(ALIGN(drawable->h, 2) / 2, 64);
+ } else {
+ buffer_width = drawable->w;
+ buffer_height = drawable->h;
+ }
+
+ /* Release the buffer storage now in case we have to return early
+ * due to failure to allocate new storage.
+ */
+ if (buffer->attachment == __DRI_BUFFER_HIZ) {
+ intel_miptree_release(&rb->mt->hiz_mt);
+ } else {
+ intel_miptree_release(&rb->mt);
+ }
+
+ struct intel_region *region =
+ intel_region_alloc_for_handle(intel->intelScreen,
+ buffer->cpp,
+ buffer_width,
+ buffer_height,
+ buffer->pitch / buffer->cpp,
+ buffer->name,
+ buffer_name);
+ if (!region)
+ return;
+
+ struct intel_mipmap_tree *mt =
+ intel_miptree_create_for_region(intel,
+ GL_TEXTURE_2D,
+ rb->Base.Format,
+ region);
+ intel_region_release(®ion);
+
+ /* Associate buffer with new storage. */
+ if (buffer->attachment == __DRI_BUFFER_HIZ) {
+ rb->mt->hiz_mt = mt;
+ } else {
+ rb->mt = mt;
+ }
+}
+
+/**
+ * \brief Verify that the X driver supports hiz and separate stencil.
+ *
+ * This implements the cleanup stage of the handshake described in the
+ * comments for 'enum intel_dri2_has_hiz'.
+ *
+ * This should be called from intel_update_renderbuffers() after 1) the
+ * DRIdrawable has been queried for its buffers via DRI2GetBuffersWithFormat()
+ * and 2) the DRM region of each returned DRIbuffer has been assigned to the
+ * appropriate intel_renderbuffer. Furthermore, this should be called *only*
+ * when 1) intel_update_renderbuffers() tried to used the X driver's separate
+ * stencil functionality and 2) it has not yet been determined if the X driver
+ * supports separate stencil.
+ *
+ * If we determine that the X driver does have support, then we set
+ * intel_screen.dri2_has_hiz to true and return.
+ *
+ * If we determine that the X driver lacks support, and we requested
+ * a DRI2BufferDepth and DRI2BufferStencil, then we must remedy the mistake by
+ * taking the following actions:
+ * 1. Discard the framebuffer's stencil and depth renderbuffers.
+ * 2. Create a combined depth/stencil renderbuffer and attach
+ * it to the framebuffer's depth and stencil attachment points.
+ * 3. Query the drawable for a new set of buffers, which consists of the
+ * originally requested set plus DRI2BufferDepthStencil.
+ * 4. Assign the DRI2BufferDepthStencil's DRM region to the new
+ * depth/stencil renderbuffer.
+ *
+ * \pre intel->intelScreen->dri2_has_hiz == INTEL_DRI2_HAS_HIZ_UNKNOWN
+ *
+ * \param drawable Drawable whose buffers were queried.
+ *
+ * \param buffers [in/out] As input, the buffer list returned by the
+ * original DRI2 query. As output, the current buffer
+ * list, which may have been altered by a new DRI2 query.
+ *
+ * \param attachments [in/out] As input, the attachment list submitted
+ * in the original DRI2 query. As output, the attachment
+ * list that was submitted in the DRI2 query that
+ * obtained the current buffer list, as returned in the
+ * output parameter \c buffers. (Note: If no new query
+ * was made, then the list remains unaltered).
+ *
+ * \param count [out] Number of buffers in the current buffer list, as
+ * returned in the output parameter \c buffers.
+ *
+ * \see enum intel_dri2_has_hiz
+ * \see struct intel_screen::dri2_has_hiz
+ * \see intel_update_renderbuffers
+ */
+static void
+intel_verify_dri2_has_hiz(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer **buffers,
+ unsigned **attachments,
+ int *count)
+{
+ assert(intel->intelScreen->dri2_has_hiz == INTEL_DRI2_HAS_HIZ_UNKNOWN);
+
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+ struct intel_renderbuffer *stencil_rb =
+ intel_get_renderbuffer(fb, BUFFER_STENCIL);
+
+ if (stencil_rb) {
+ /*
+ * We requested a DRI2BufferStencil without knowing if the X driver
+ * supports it. Now, check if X handled the request correctly and clean
+ * up if it did not. (See comments for 'enum intel_dri2_has_hiz').
+ */
+ struct intel_renderbuffer *depth_rb =
+ intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ assert(stencil_rb->Base.Format == MESA_FORMAT_S8);
+ assert(depth_rb && depth_rb->Base.Format == MESA_FORMAT_X8_Z24);
+
+ if (stencil_rb->mt->region->tiling == I915_TILING_NONE) {
+ /*
+ * The stencil buffer is actually W tiled. The region's tiling is
+ * I915_TILING_NONE, however, because the GTT is incapable of W
+ * fencing.
+ */
+ intel->intelScreen->dri2_has_hiz = INTEL_DRI2_HAS_HIZ_TRUE;
+ return;
+ } else {
+ /*
+ * Oops... the screen doesn't support separate stencil. Discard the
+ * separate depth and stencil buffers and replace them with
+ * a combined depth/stencil buffer. Discard the hiz buffer too.
+ */
+ intel->intelScreen->dri2_has_hiz = INTEL_DRI2_HAS_HIZ_FALSE;
+ if (intel->must_use_separate_stencil) {
+ _mesa_problem(&intel->ctx,
+ "intel_context requires separate stencil, but the "
+ "DRIscreen does not support it. You may need to "
+ "upgrade the Intel X driver to 2.16.0");
+ abort();
+ }
+
+ /* 1. Discard depth and stencil renderbuffers. */
+ _mesa_remove_renderbuffer(fb, BUFFER_DEPTH);
+ depth_rb = NULL;
+ _mesa_remove_renderbuffer(fb, BUFFER_STENCIL);
+ stencil_rb = NULL;
+
+ /* 2. Create new depth/stencil renderbuffer. */
+ struct intel_renderbuffer *depth_stencil_rb =
+ intel_create_renderbuffer(MESA_FORMAT_S8_Z24);
+ _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depth_stencil_rb->Base);
+ _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &depth_stencil_rb->Base);
+
+ /* 3. Append DRI2BufferDepthStencil to attachment list. */
+ int old_count = *count;
+ unsigned int *old_attachments = *attachments;
+ *count = old_count + 1;
+ *attachments = malloc(2 * (*count) * sizeof(unsigned));
+ memcpy(*attachments, old_attachments, 2 * old_count * sizeof(unsigned));
+ free(old_attachments);
+ (*attachments)[2 * old_count + 0] = __DRI_BUFFER_DEPTH_STENCIL;
+ (*attachments)[2 * old_count + 1] = intel_bits_per_pixel(depth_stencil_rb);
+
+ /* 4. Request new set of DRI2 attachments. */
+ __DRIscreen *screen = intel->intelScreen->driScrnPriv;
+ *buffers = screen->dri2.loader->getBuffersWithFormat(drawable,
+ &drawable->w,
+ &drawable->h,
+ *attachments,
+ *count,
+ count,
+ drawable->loaderPrivate);
+ if (!*buffers)
+ return;
+
+ /*
+ * I don't know how to recover from the failure assertion below.
+ * Rather than fail gradually and unexpectedly, we should just die
+ * now.
+ */
+ assert(*count == old_count + 1);
+
+ /* 5. Assign the DRI buffer's DRM region to the its renderbuffers. */
+ __DRIbuffer *depth_stencil_buffer = NULL;
+ for (int i = 0; i < *count; ++i) {
+ if ((*buffers)[i].attachment == __DRI_BUFFER_DEPTH_STENCIL) {
+ depth_stencil_buffer = &(*buffers)[i];
+ break;
+ }
+ }
+ struct intel_region *region =
+ intel_region_alloc_for_handle(intel->intelScreen,
+ depth_stencil_buffer->cpp,
+ drawable->w,
+ drawable->h,
+ depth_stencil_buffer->pitch
+ / depth_stencil_buffer->cpp,
+ depth_stencil_buffer->name,
+ "dri2 depth / stencil buffer");
+ if (!region)
+ return;
+
+ struct intel_mipmap_tree *mt =
+ intel_miptree_create_for_region(intel,
+ GL_TEXTURE_2D,
+ depth_stencil_rb->Base.Format,
+ region);
+ intel_region_release(®ion);
+ if (!mt)
+ return;
+
+ intel_miptree_reference(&intel_get_renderbuffer(fb, BUFFER_DEPTH)->mt, mt);
+ intel_miptree_reference(&intel_get_renderbuffer(fb, BUFFER_STENCIL)->mt, mt);
+ intel_miptree_release(&mt);
+ }
+ }
+
+ if (intel_framebuffer_has_hiz(fb)) {
+ /*
+ * In the future, the driver may advertise a GL config with hiz
+ * compatible depth bits and 0 stencil bits (for example, when the
+ * driver gains support for float32 depth buffers). When that day comes,
+ * here we need to verify that the X driver does in fact support hiz and
+ * clean up if it doesn't.
+ *
+ * Presently, however, no verification or clean up is necessary, and
+ * execution should not reach here. If the framebuffer still has a hiz
+ * region, then we have already set dri2_has_hiz to true after
+ * confirming above that the stencil buffer is W tiled.
+ */
+ assert(0);
+ }
}