/** * For a singlesample image buffer, this simply wraps the given region with a miptree. * * For a multisample image buffer, this wraps the given region with * a singlesample miptree, then creates a multisample miptree into which the * singlesample miptree is embedded as a child. */ struct intel_mipmap_tree* intel_miptree_create_for_image_buffer(struct intel_context *intel, enum __DRIimageBufferMask buffer_type, mesa_format format, uint32_t num_samples, struct intel_region *region) { struct intel_mipmap_tree *mt = NULL; /* Only the front and back buffers, which are color buffers, are allocated * through the image loader. */ assert(_mesa_get_format_base_format(format) == GL_RGB || _mesa_get_format_base_format(format) == GL_RGBA); mt = intel_miptree_create_for_bo(intel, region->bo, format, 0, region->width, region->height, region->pitch, region->tiling); return mt; }
/** * For a singlesample DRI2 buffer, this simply wraps the given region with a miptree. * * For a multisample DRI2 buffer, this wraps the given region with * a singlesample miptree, then creates a multisample miptree into which the * singlesample miptree is embedded as a child. */ struct intel_mipmap_tree* intel_miptree_create_for_dri2_buffer(struct intel_context *intel, unsigned dri_attachment, mesa_format format, struct intel_region *region) { struct intel_mipmap_tree *mt = NULL; /* Only the front and back buffers, which are color buffers, are shared * through DRI2. */ assert(dri_attachment == __DRI_BUFFER_BACK_LEFT || dri_attachment == __DRI_BUFFER_FRONT_LEFT || dri_attachment == __DRI_BUFFER_FAKE_FRONT_LEFT); assert(_mesa_get_format_base_format(format) == GL_RGB || _mesa_get_format_base_format(format) == GL_RGBA); mt = intel_miptree_create_for_bo(intel, region->bo, format, 0, region->width, region->height, region->pitch, region->tiling); if (!mt) return NULL; mt->region->name = region->name; return mt; }
static bool intel_set_texture_storage_for_buffer_object(struct gl_context *ctx, struct gl_texture_object *tex_obj, struct gl_buffer_object *buffer_obj, uint32_t buffer_offset, uint32_t row_stride, bool read_only) { struct brw_context *brw = brw_context(ctx); struct intel_texture_object *intel_texobj = intel_texture_object(tex_obj); struct gl_texture_image *image = tex_obj->Image[0][0]; struct intel_texture_image *intel_image = intel_texture_image(image); struct intel_buffer_object *intel_buffer_obj = intel_buffer_object(buffer_obj); if (!read_only) { /* Renderbuffers have the restriction that the buffer offset and * surface pitch must be a multiple of the element size. If it's * not, we have to fail and fall back to software. */ int cpp = _mesa_get_format_bytes(image->TexFormat); if (buffer_offset % cpp || row_stride % cpp) { perf_debug("Bad PBO alignment; fallback to CPU mapping\n"); return false; } if (!brw->format_supported_as_render_target[image->TexFormat]) { perf_debug("Non-renderable PBO format; fallback to CPU mapping\n"); return false; } } assert(intel_texobj->mt == NULL); drm_intel_bo *bo = intel_bufferobj_buffer(brw, intel_buffer_obj, buffer_offset, row_stride * image->Height); intel_texobj->mt = intel_miptree_create_for_bo(brw, bo, image->TexFormat, buffer_offset, image->Width, image->Height, image->Depth, row_stride, 0); if (!intel_texobj->mt) return false; if (!_swrast_init_texture_image(image)) return false; intel_miptree_reference(&intel_image->mt, intel_texobj->mt); /* The miptree is in a validated state, so no need to check later. */ intel_texobj->needs_validate = false; intel_texobj->validated_first_level = 0; intel_texobj->validated_last_level = 0; intel_texobj->_Format = intel_texobj->mt->format; return true; }
/** * Binds a BO to a texture image, as if it was uploaded by glTexImage2D(). * * Used for GLX_EXT_texture_from_pixmap and EGL image extensions, */ static void intel_set_texture_image_bo(struct gl_context *ctx, struct gl_texture_image *image, drm_intel_bo *bo, GLenum target, GLenum internalFormat, mesa_format format, uint32_t offset, GLuint width, GLuint height, GLuint pitch, GLuint tile_x, GLuint tile_y, uint32_t layout_flags) { struct brw_context *brw = brw_context(ctx); struct intel_texture_image *intel_image = intel_texture_image(image); struct gl_texture_object *texobj = image->TexObject; struct intel_texture_object *intel_texobj = intel_texture_object(texobj); uint32_t draw_x, draw_y; _mesa_init_teximage_fields(&brw->ctx, image, width, height, 1, 0, internalFormat, format); ctx->Driver.FreeTextureImageBuffer(ctx, image); intel_image->mt = intel_miptree_create_for_bo(brw, bo, image->TexFormat, 0, width, height, 1, pitch, layout_flags); if (intel_image->mt == NULL) return; intel_image->mt->target = target; intel_image->mt->total_width = width; intel_image->mt->total_height = height; intel_image->mt->level[0].slice[0].x_offset = tile_x; intel_image->mt->level[0].slice[0].y_offset = tile_y; intel_miptree_get_tile_offsets(intel_image->mt, 0, 0, &draw_x, &draw_y); /* From "OES_EGL_image" error reporting. We report GL_INVALID_OPERATION * for EGL images from non-tile aligned sufaces in gen4 hw and earlier which has * trouble resolving back to destination image due to alignment issues. */ if (!brw->has_surface_tile_offset && (draw_x != 0 || draw_y != 0)) { _mesa_error(ctx, GL_INVALID_OPERATION, __func__); intel_miptree_release(&intel_image->mt); return; } intel_texobj->needs_validate = true; intel_image->mt->offset = offset; assert(pitch % intel_image->mt->cpp == 0); intel_image->base.RowStride = pitch / intel_image->mt->cpp; /* Immediately validate the image to the object. */ intel_miptree_reference(&intel_texobj->mt, intel_image->mt); }
static void intel_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, void *image_handle) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb; __DRIscreen *screen; __DRIimage *image; screen = intel->intelScreen->driScrnPriv; image = screen->dri2.image->lookupEGLImage(screen, image_handle, screen->loaderPrivate); if (image == NULL) return; /* __DRIimage is opaque to the core so it has to be checked here */ switch (image->format) { case MESA_FORMAT_R8G8B8A8_UNORM: _mesa_error(&intel->ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(unsupported image format"); return; break; default: break; } irb = intel_renderbuffer(rb); intel_miptree_release(&irb->mt); irb->mt = intel_miptree_create_for_bo(intel, image->region->bo, image->format, image->offset, image->region->width, image->region->height, image->region->pitch, image->region->tiling); if (!irb->mt) return; rb->InternalFormat = image->internal_format; rb->Width = image->region->width; rb->Height = image->region->height; rb->Format = image->format; rb->_BaseFormat = _mesa_base_fbo_format(&intel->ctx, image->internal_format); rb->NeedsFinishRenderTexture = true; }
/** * Binds a BO to a texture image, as if it was uploaded by glTexImage2D(). * * Used for GLX_EXT_texture_from_pixmap and EGL image extensions, */ static struct intel_mipmap_tree * create_mt_for_dri_image(struct brw_context *brw, GLenum target, __DRIimage *image) { struct intel_mipmap_tree *mt; uint32_t draw_x, draw_y; /* Disable creation of the texture's aux buffers because the driver exposes * no EGL API to manage them. That is, there is no API for resolving the aux * buffer's content to the main buffer nor for invalidating the aux buffer's * content. */ mt = intel_miptree_create_for_bo(brw, image->bo, image->format, 0, image->width, image->height, 1, image->pitch, MIPTREE_LAYOUT_DISABLE_AUX); if (mt == NULL) return NULL; mt->target = target; mt->total_width = image->width; mt->total_height = image->height; mt->level[0].slice[0].x_offset = image->tile_x; mt->level[0].slice[0].y_offset = image->tile_y; intel_miptree_get_tile_offsets(mt, 0, 0, &draw_x, &draw_y); /* From "OES_EGL_image" error reporting. We report GL_INVALID_OPERATION * for EGL images from non-tile aligned sufaces in gen4 hw and earlier which has * trouble resolving back to destination image due to alignment issues. */ if (!brw->has_surface_tile_offset && (draw_x != 0 || draw_y != 0)) { _mesa_error(&brw->ctx, GL_INVALID_OPERATION, __func__); intel_miptree_release(&mt); return NULL; } mt->offset = image->offset; return mt; }
static struct intel_mipmap_tree * create_mt_for_planar_dri_image(struct brw_context *brw, GLenum target, __DRIimage *image) { struct intel_image_format *f = image->planar_format; struct intel_mipmap_tree *planar_mt; for (int i = 0; i < f->nplanes; i++) { const int index = f->planes[i].buffer_index; const uint32_t dri_format = f->planes[i].dri_format; const mesa_format format = driImageFormatToGLFormat(dri_format); const uint32_t width = image->width >> f->planes[i].width_shift; const uint32_t height = image->height >> f->planes[i].height_shift; /* Disable creation of the texture's aux buffers because the driver * exposes no EGL API to manage them. That is, there is no API for * resolving the aux buffer's content to the main buffer nor for * invalidating the aux buffer's content. */ struct intel_mipmap_tree *mt = intel_miptree_create_for_bo(brw, image->bo, format, image->offsets[index], width, height, 1, image->strides[index], MIPTREE_LAYOUT_DISABLE_AUX); if (mt == NULL) return NULL; mt->target = target; mt->total_width = width; mt->total_height = height; if (i == 0) planar_mt = mt; else planar_mt->plane[i - 1] = mt; } return planar_mt; }
/* XXX: Do this for TexSubImage also: */ static bool try_pbo_upload(struct gl_context *ctx, struct gl_texture_image *image, const struct gl_pixelstore_attrib *unpack, GLenum format, GLenum type, const void *pixels) { struct intel_texture_image *intelImage = intel_texture_image(image); struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); GLuint src_offset; drm_intel_bo *src_buffer; if (!_mesa_is_bufferobj(unpack->BufferObj)) return false; DBG("trying pbo upload\n"); if (intel->ctx._ImageTransferState || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: image transfer\n", __FUNCTION__); return false; } ctx->Driver.AllocTextureImageBuffer(ctx, image); if (!intelImage->mt) { DBG("%s: no miptree\n", __FUNCTION__); return false; } if (!_mesa_format_matches_format_and_type(intelImage->mt->format, format, type, false)) { DBG("%s: format mismatch (upload to %s with format 0x%x, type 0x%x)\n", __FUNCTION__, _mesa_get_format_name(intelImage->mt->format), format, type); return false; } if (image->TexObject->Target == GL_TEXTURE_1D_ARRAY || image->TexObject->Target == GL_TEXTURE_2D_ARRAY) { DBG("%s: no support for array textures\n", __FUNCTION__); return false; } src_buffer = intel_bufferobj_source(intel, pbo, 64, &src_offset); /* note: potential 64-bit ptr to 32-bit int cast */ src_offset += (GLuint) (unsigned long) pixels; int src_stride = _mesa_image_row_stride(unpack, image->Width, format, type); struct intel_mipmap_tree *pbo_mt = intel_miptree_create_for_bo(intel, src_buffer, intelImage->mt->format, src_offset, image->Width, image->Height, src_stride, I915_TILING_NONE); if (!pbo_mt) return false; if (!intel_miptree_blit(intel, pbo_mt, 0, 0, 0, 0, false, intelImage->mt, image->Level, image->Face, 0, 0, false, image->Width, image->Height, GL_COPY)) { DBG("%s: blit failed\n", __FUNCTION__); intel_miptree_release(&pbo_mt); return false; } intel_miptree_release(&pbo_mt); DBG("%s: success\n", __FUNCTION__); return true; }
static bool do_blit_drawpixels(struct gl_context * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct brw_context *brw = brw_context(ctx); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; drm_intel_bo *src_buffer; DBG("%s\n", __FUNCTION__); if (!intel_check_blit_fragment_ops(ctx, false)) return false; if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) { DBG("%s: fallback due to MRT\n", __FUNCTION__); return false; } struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (!_mesa_format_matches_format_and_type(irb->mt->format, format, type, false)) { DBG("%s: bad format for blit\n", __FUNCTION__); return false; } if (unpack->SwapBytes || unpack->LsbFirst || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: bad packing params\n", __FUNCTION__); return false; } int src_stride = _mesa_image_row_stride(unpack, width, format, type); bool src_flip = false; /* Mesa flips the src_stride for unpack->Invert, but we want our mt to have * a normal src_stride. */ if (unpack->Invert) { src_stride = -src_stride; src_flip = true; } src_offset = (GLintptr)pixels; src_offset += _mesa_image_offset(2, unpack, width, height, format, type, 0, 0, 0); intel_prepare_render(brw); src_buffer = intel_bufferobj_buffer(brw, src, src_offset, width * height * irb->mt->cpp); struct intel_mipmap_tree *pbo_mt = intel_miptree_create_for_bo(brw, src_buffer, irb->mt->format, src_offset, width, height, src_stride, I915_TILING_NONE); if (!pbo_mt) return false; if (!intel_miptree_blit(brw, pbo_mt, 0, 0, 0, 0, src_flip, irb->mt, irb->mt_level, irb->mt_layer, x, y, _mesa_is_winsys_fbo(ctx->DrawBuffer), width, height, GL_COPY)) { DBG("%s: blit failed\n", __FUNCTION__); intel_miptree_release(&pbo_mt); return false; } intel_miptree_release(&pbo_mt); if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += width * height; intel_check_front_buffer_rendering(brw); DBG("%s: success\n", __FUNCTION__); return true; }
static void intel_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, void *image_handle) { struct brw_context *brw = brw_context(ctx); struct intel_renderbuffer *irb; __DRIscreen *screen; __DRIimage *image; screen = brw->intelScreen->driScrnPriv; image = screen->dri2.image->lookupEGLImage(screen, image_handle, screen->loaderPrivate); if (image == NULL) return; if (image->planar_format && image->planar_format->nplanes > 1) { _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(planar buffers are not " "supported as render targets."); return; } /* Buffers originating from outside are for read-only. */ if (image->dma_buf_imported) { _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(dma buffers are read-only)"); return; } /* __DRIimage is opaque to the core so it has to be checked here */ switch (image->format) { case MESA_FORMAT_RGBA8888_REV: _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(unsupported image format"); return; break; default: break; } irb = intel_renderbuffer(rb); intel_miptree_release(&irb->mt); irb->mt = intel_miptree_create_for_bo(brw, image->region->bo, image->format, image->offset, image->region->width, image->region->height, image->region->pitch, image->region->tiling); if (!irb->mt) return; rb->InternalFormat = image->internal_format; rb->Width = image->region->width; rb->Height = image->region->height; rb->Format = image->format; rb->_BaseFormat = _mesa_base_fbo_format(ctx, image->internal_format); rb->NeedsFinishRenderTexture = true; }
void intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint texture_format, __DRIdrawable *dPriv) { struct gl_framebuffer *fb = dPriv->driverPrivate; struct brw_context *brw = pDRICtx->driverPrivate; struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *rb; struct gl_texture_object *texObj; struct gl_texture_image *texImage; mesa_format texFormat = MESA_FORMAT_NONE; struct intel_mipmap_tree *mt; GLenum internal_format = 0; texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; if (dPriv->lastStamp != dPriv->dri2.stamp || !pDRICtx->driScreenPriv->dri2.useInvalidate) intel_update_renderbuffers(pDRICtx, dPriv); rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); /* If the miptree isn't set, then intel_update_renderbuffers was unable * to get the BO for the drawable from the window system. */ if (!rb || !rb->mt) return; if (rb->mt->cpp == 4) { if (texture_format == __DRI_TEXTURE_FORMAT_RGB) { internal_format = GL_RGB; texFormat = MESA_FORMAT_B8G8R8X8_UNORM; } else { internal_format = GL_RGBA; texFormat = MESA_FORMAT_B8G8R8A8_UNORM; } } else if (rb->mt->cpp == 2) { internal_format = GL_RGB; texFormat = MESA_FORMAT_B5G6R5_UNORM; } intel_miptree_make_shareable(brw, rb->mt); mt = intel_miptree_create_for_bo(brw, rb->mt->bo, texFormat, 0, rb->Base.Base.Width, rb->Base.Base.Height, 1, rb->mt->pitch, 0); if (mt == NULL) return; mt->target = target; mt->total_width = rb->Base.Base.Width; mt->total_height = rb->Base.Base.Height; _mesa_lock_texture(&brw->ctx, texObj); texImage = _mesa_get_tex_image(ctx, texObj, target, 0); intel_set_texture_image_mt(brw, texImage, internal_format, mt); intel_miptree_release(&mt); _mesa_unlock_texture(&brw->ctx, texObj); }
static bool do_blit_readpixels(struct gl_context * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid * pixels) { struct brw_context *brw = brw_context(ctx); struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj); GLuint dst_offset; drm_intel_bo *dst_buffer; GLint dst_x, dst_y; GLuint dirty; DBG("%s\n", __FUNCTION__); assert(_mesa_is_bufferobj(pack->BufferObj)); struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (ctx->_ImageTransferState || !_mesa_format_matches_format_and_type(irb->mt->format, format, type, false)) { DBG("%s - bad format for blit\n", __FUNCTION__); return false; } if (pack->SwapBytes || pack->LsbFirst) { DBG("%s: bad packing params\n", __FUNCTION__); return false; } int dst_stride = _mesa_image_row_stride(pack, width, format, type); bool dst_flip = false; /* Mesa flips the dst_stride for pack->Invert, but we want our mt to have a * normal dst_stride. */ struct gl_pixelstore_attrib uninverted_pack = *pack; if (pack->Invert) { dst_stride = -dst_stride; dst_flip = true; uninverted_pack.Invert = false; } dst_offset = (GLintptr)pixels; dst_offset += _mesa_image_offset(2, &uninverted_pack, width, height, format, type, 0, 0, 0); if (!_mesa_clip_copytexsubimage(ctx, &dst_x, &dst_y, &x, &y, &width, &height)) { return true; } dirty = brw->front_buffer_dirty; intel_prepare_render(brw); brw->front_buffer_dirty = dirty; dst_buffer = intel_bufferobj_buffer(brw, dst, dst_offset, height * dst_stride); struct intel_mipmap_tree *pbo_mt = intel_miptree_create_for_bo(brw, dst_buffer, irb->mt->format, dst_offset, width, height, dst_stride, I915_TILING_NONE); if (!intel_miptree_blit(brw, irb->mt, irb->mt_level, irb->mt_layer, x, y, _mesa_is_winsys_fbo(ctx->ReadBuffer), pbo_mt, 0, 0, 0, 0, dst_flip, width, height, GL_COPY)) { return false; } intel_miptree_release(&pbo_mt); DBG("%s - DONE\n", __FUNCTION__); return true; }