X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_cb_texture.c;h=1847cc30df9e752ae60b00b4fe806ba90c1cc9da;hb=f4d5e55dd1cb4617ee18387d2aff337676b420c4;hp=a18b08b32267768ed43a086a9935ad09058bba22;hpb=d04bb14d04d2f2f03cdaa3d78121d338a81de2e4;p=mesa.git diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index a18b08b3226..1847cc30df9 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -48,14 +48,17 @@ #include "state_tracker/st_debug.h" #include "state_tracker/st_context.h" +#include "state_tracker/st_cb_bitmap.h" #include "state_tracker/st_cb_fbo.h" #include "state_tracker/st_cb_flush.h" #include "state_tracker/st_cb_texture.h" #include "state_tracker/st_cb_bufferobjects.h" #include "state_tracker/st_format.h" +#include "state_tracker/st_pbo.h" #include "state_tracker/st_texture.h" #include "state_tracker/st_gen_mipmap.h" #include "state_tracker/st_atom.h" +#include "state_tracker/st_sampler_view.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" @@ -151,6 +154,8 @@ st_NewTextureObject(struct gl_context * ctx, GLuint name, GLenum target) DBG("%s\n", __func__); _mesa_initialize_texture_object(ctx, &obj->base, name, target); + obj->needs_validation = true; + return &obj->base; } @@ -174,6 +179,8 @@ static void st_FreeTextureImageBuffer(struct gl_context *ctx, struct gl_texture_image *texImage) { + struct st_context *st = st_context(ctx); + struct st_texture_object *stObj = st_texture_object(texImage->TexObject); struct st_texture_image *stImage = st_texture_image(texImage); DBG("%s\n", __func__); @@ -185,8 +192,44 @@ st_FreeTextureImageBuffer(struct gl_context *ctx, free(stImage->transfer); stImage->transfer = NULL; stImage->num_transfers = 0; + + if (stImage->etc_data) { + free(stImage->etc_data); + stImage->etc_data = NULL; + } + + /* if the texture image is being deallocated, the structure of the + * texture is changing so we'll likely need a new sampler view. + */ + st_texture_release_all_sampler_views(st, stObj); +} + +bool +st_etc_fallback(struct st_context *st, struct gl_texture_image *texImage) +{ + return (_mesa_is_format_etc2(texImage->TexFormat) && !st->has_etc2) || + (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8 && !st->has_etc1); } +static void +etc_fallback_allocate(struct st_context *st, struct st_texture_image *stImage) +{ + struct gl_texture_image *texImage = &stImage->base; + + if (!st_etc_fallback(st, texImage)) + return; + + if (stImage->etc_data) + free(stImage->etc_data); + + unsigned data_size = _mesa_format_image_size(texImage->TexFormat, + texImage->Width2, + texImage->Height2, + texImage->Depth2); + + stImage->etc_data = + malloc(data_size * _mesa_num_tex_faces(texImage->TexObject->Target)); +} /** called via ctx->Driver.MapTextureImage() */ static void @@ -213,26 +256,24 @@ st_MapTextureImage(struct gl_context *ctx, map = st_texture_image_map(st, stImage, pipeMode, x, y, slice, w, h, 1, &transfer); if (map) { - if ((_mesa_is_format_etc2(texImage->TexFormat) && !st->has_etc2) || - (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8 && !st->has_etc1)) { - /* ETC isn't supported by gallium and it's represented - * by uncompressed formats. Only write transfers with precompressed - * data are supported by ES3, which makes this really simple. + if (st_etc_fallback(st, texImage)) { + /* ETC isn't supported by all gallium drivers, where it's represented + * by uncompressed formats. We store the compressed data (as it's + * needed for image copies in OES_copy_image), and decompress as + * necessary in Unmap. * - * Just create a temporary storage where the ETC texture will - * be stored. It will be decompressed in the Unmap function. + * Note: all ETC1/ETC2 formats have 4x4 block sizes. */ unsigned z = transfer->box.z; struct st_texture_image_transfer *itransfer = &stImage->transfer[z]; - itransfer->temp_data = - malloc(_mesa_format_image_size(texImage->TexFormat, w, h, 1)); - itransfer->temp_stride = - _mesa_format_row_stride(texImage->TexFormat, w); + unsigned bytes = _mesa_get_format_bytes(texImage->TexFormat); + unsigned stride = *rowStrideOut = itransfer->temp_stride = + _mesa_format_row_stride(texImage->TexFormat, texImage->Width2); + *mapOut = itransfer->temp_data = + stImage->etc_data + ((x / 4) * bytes + (y / 4) * stride) + + z * stride * texImage->Height2 / 4; itransfer->map = map; - - *mapOut = itransfer->temp_data; - *rowStrideOut = itransfer->temp_stride; } else { /* supported mapping */ @@ -256,8 +297,7 @@ st_UnmapTextureImage(struct gl_context *ctx, struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); - if ((_mesa_is_format_etc2(texImage->TexFormat) && !st->has_etc2) || - (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8 && !st->has_etc1)) { + if (st_etc_fallback(st, texImage)) { /* Decompress the ETC texture to the mapped one. */ unsigned z = slice + stImage->base.Face; struct st_texture_image_transfer *itransfer = &stImage->transfer[z]; @@ -265,20 +305,21 @@ st_UnmapTextureImage(struct gl_context *ctx, assert(z == transfer->box.z); - if (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8) { - _mesa_etc1_unpack_rgba8888(itransfer->map, transfer->stride, - itransfer->temp_data, - itransfer->temp_stride, - transfer->box.width, transfer->box.height); - } - else { - _mesa_unpack_etc2_format(itransfer->map, transfer->stride, - itransfer->temp_data, itransfer->temp_stride, - transfer->box.width, transfer->box.height, - texImage->TexFormat); + if (transfer->usage & PIPE_TRANSFER_WRITE) { + if (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8) { + _mesa_etc1_unpack_rgba8888(itransfer->map, transfer->stride, + itransfer->temp_data, + itransfer->temp_stride, + transfer->box.width, transfer->box.height); + } + else { + _mesa_unpack_etc2_format(itransfer->map, transfer->stride, + itransfer->temp_data, itransfer->temp_stride, + transfer->box.width, transfer->box.height, + texImage->TexFormat); + } } - free(itransfer->temp_data); itransfer->temp_data = NULL; itransfer->temp_stride = 0; itransfer->map = 0; @@ -455,23 +496,47 @@ guess_and_alloc_texture(struct st_context *st, struct st_texture_object *stObj, const struct st_texture_image *stImage) { + const struct gl_texture_image *firstImage; GLuint lastLevel, width, height, depth; GLuint bindings; - GLuint ptWidth, ptHeight, ptDepth, ptLayers; + unsigned ptWidth; + uint16_t ptHeight, ptDepth, ptLayers; enum pipe_format fmt; + bool guessed_box = false; DBG("%s\n", __func__); assert(!stObj->pt); - if (!guess_base_level_size(stObj->base.Target, - stImage->base.Width2, - stImage->base.Height2, - stImage->base.Depth2, - stImage->base.Level, - &width, &height, &depth)) { + /* If a base level image with compatible size exists, use that as our guess. + */ + firstImage = _mesa_base_tex_image(&stObj->base); + if (firstImage && + firstImage->Width2 > 0 && + firstImage->Height2 > 0 && + firstImage->Depth2 > 0 && + guess_base_level_size(stObj->base.Target, + firstImage->Width2, + firstImage->Height2, + firstImage->Depth2, + firstImage->Level, + &width, &height, &depth)) { + if (stImage->base.Width2 == u_minify(width, stImage->base.Level) && + stImage->base.Height2 == u_minify(height, stImage->base.Level) && + stImage->base.Depth2 == u_minify(depth, stImage->base.Level)) + guessed_box = true; + } + + if (!guessed_box) + guessed_box = guess_base_level_size(stObj->base.Target, + stImage->base.Width2, + stImage->base.Height2, + stImage->base.Depth2, + stImage->base.Level, + &width, &height, &depth); + + if (!guessed_box) { /* we can't determine the image size at level=0 */ - stObj->width0 = stObj->height0 = stObj->depth0 = 0; /* this is not an out of memory error */ return GL_TRUE; } @@ -496,11 +561,6 @@ guess_and_alloc_texture(struct st_context *st, lastLevel = 0; } - /* Save the level=0 dimensions */ - stObj->width0 = width; - stObj->height0 = height; - stObj->depth0 = depth; - fmt = st_mesa_format_to_pipe_format(st, stImage->base.TexFormat); bindings = default_bindings(st, fmt); @@ -548,6 +608,10 @@ st_AllocTextureImageBuffer(struct gl_context *ctx, assert(!stImage->pt); /* xxx this might be wrong */ + stObj->needs_validation = true; + + etc_fallback_allocate(st, stImage); + /* Look if the parent texture object has space for this image */ if (stObj->pt && level <= stObj->pt->last_level && @@ -590,7 +654,8 @@ st_AllocTextureImageBuffer(struct gl_context *ctx, enum pipe_format format = st_mesa_format_to_pipe_format(st, texImage->TexFormat); GLuint bindings = default_bindings(st, format); - GLuint ptWidth, ptHeight, ptDepth, ptLayers; + unsigned ptWidth; + uint16_t ptHeight, ptDepth, ptLayers; st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, @@ -690,59 +755,6 @@ st_get_blit_mask(GLenum srcFormat, GLenum dstFormat) } } -void -st_init_pbo_upload(struct st_context *st) -{ - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; - - st->pbo_upload.enabled = - screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS) && - screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT) >= 1 && - screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_INTEGERS); - if (!st->pbo_upload.enabled) - return; - - st->pbo_upload.rgba_only = - screen->get_param(screen, PIPE_CAP_BUFFER_SAMPLER_VIEW_RGBA_ONLY); - - if (screen->get_param(screen, PIPE_CAP_TGSI_INSTANCEID)) { - if (screen->get_param(screen, PIPE_CAP_TGSI_VS_LAYER_VIEWPORT)) { - st->pbo_upload.upload_layers = true; - } else if (screen->get_param(screen, PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES) >= 3) { - st->pbo_upload.upload_layers = true; - st->pbo_upload.use_gs = true; - } - } - - /* Blend state */ - memset(&st->pbo_upload.blend, 0, sizeof(struct pipe_blend_state)); - st->pbo_upload.blend.rt[0].colormask = PIPE_MASK_RGBA; - - /* Rasterizer state */ - memset(&st->pbo_upload.raster, 0, sizeof(struct pipe_rasterizer_state)); - st->pbo_upload.raster.half_pixel_center = 1; -} - -void -st_destroy_pbo_upload(struct st_context *st) -{ - if (st->pbo_upload.fs) { - cso_delete_fragment_shader(st->cso_context, st->pbo_upload.fs); - st->pbo_upload.fs = NULL; - } - - if (st->pbo_upload.gs) { - cso_delete_geometry_shader(st->cso_context, st->pbo_upload.gs); - st->pbo_upload.gs = NULL; - } - - if (st->pbo_upload.vs) { - cso_delete_vertex_shader(st->cso_context, st->pbo_upload.vs); - st->pbo_upload.vs = NULL; - } -} - /** * Converts format to a format with the same components, types * and sizes, but with the components in RGBA order. @@ -900,10 +912,10 @@ format_is_alpha(enum pipe_format format) const struct util_format_description *desc = util_format_description(format); if (desc->nr_channels == 1 && - desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_0 && - desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_0 && - desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_0 && - desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) + desc->swizzle[0] == PIPE_SWIZZLE_0 && + desc->swizzle[1] == PIPE_SWIZZLE_0 && + desc->swizzle[2] == PIPE_SWIZZLE_0 && + desc->swizzle[3] == PIPE_SWIZZLE_X) return true; return false; @@ -918,10 +930,10 @@ format_is_red(enum pipe_format format) const struct util_format_description *desc = util_format_description(format); if (desc->nr_channels == 1 && - desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && - desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_0 && - desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_0 && - desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) + desc->swizzle[0] == PIPE_SWIZZLE_X && + desc->swizzle[1] == PIPE_SWIZZLE_0 && + desc->swizzle[2] == PIPE_SWIZZLE_0 && + desc->swizzle[3] == PIPE_SWIZZLE_1) return true; return false; @@ -937,10 +949,10 @@ format_is_luminance(enum pipe_format format) const struct util_format_description *desc = util_format_description(format); if (desc->nr_channels == 1 && - desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && - desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X && - desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X && - desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) + desc->swizzle[0] == PIPE_SWIZZLE_X && + desc->swizzle[1] == PIPE_SWIZZLE_X && + desc->swizzle[2] == PIPE_SWIZZLE_X && + desc->swizzle[3] == PIPE_SWIZZLE_1) return true; return false; @@ -955,10 +967,10 @@ format_is_red_alpha(enum pipe_format format) const struct util_format_description *desc = util_format_description(format); if (desc->nr_channels == 2 && - desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && - desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_0 && - desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_0 && - desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_Y) + desc->swizzle[0] == PIPE_SWIZZLE_X && + desc->swizzle[1] == PIPE_SWIZZLE_0 && + desc->swizzle[2] == PIPE_SWIZZLE_0 && + desc->swizzle[3] == PIPE_SWIZZLE_Y) return true; return false; @@ -969,10 +981,10 @@ format_is_swizzled_rgba(enum pipe_format format) { const struct util_format_description *desc = util_format_description(format); - if ((desc->swizzle[0] == TGSI_SWIZZLE_X || desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_0) && - (desc->swizzle[1] == TGSI_SWIZZLE_Y || desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_0) && - (desc->swizzle[2] == TGSI_SWIZZLE_Z || desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_0) && - (desc->swizzle[3] == TGSI_SWIZZLE_W || desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1)) + if ((desc->swizzle[0] == TGSI_SWIZZLE_X || desc->swizzle[0] == PIPE_SWIZZLE_0) && + (desc->swizzle[1] == TGSI_SWIZZLE_Y || desc->swizzle[1] == PIPE_SWIZZLE_0) && + (desc->swizzle[2] == TGSI_SWIZZLE_Z || desc->swizzle[2] == PIPE_SWIZZLE_0) && + (desc->swizzle[3] == TGSI_SWIZZLE_W || desc->swizzle[3] == PIPE_SWIZZLE_1)) return false; return true; @@ -1101,10 +1113,10 @@ reinterpret_formats(enum pipe_format *src_format, enum pipe_format *dst_format) unsigned i; /* Make sure the format is an RGBA and not an RGBX format */ - if (src_desc->nr_channels != 4 || src_desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) + if (src_desc->nr_channels != 4 || src_desc->swizzle[3] == PIPE_SWIZZLE_1) return false; - if (dst_desc->nr_channels != 4 || dst_desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) + if (dst_desc->nr_channels != 4 || dst_desc->swizzle[3] == PIPE_SWIZZLE_1) return false; for (i = 0; i < 4; i++) @@ -1122,218 +1134,21 @@ reinterpret_formats(enum pipe_format *src_format, enum pipe_format *dst_format) return true; } -static void * -create_pbo_upload_vs(struct st_context *st) -{ - struct ureg_program *ureg; - struct ureg_src in_pos; - struct ureg_src in_instanceid; - struct ureg_dst out_pos; - struct ureg_dst out_layer; - - ureg = ureg_create(TGSI_PROCESSOR_VERTEX); - if (!ureg) - return NULL; - - in_pos = ureg_DECL_vs_input(ureg, TGSI_SEMANTIC_POSITION); - - out_pos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); - - if (st->pbo_upload.upload_layers) { - in_instanceid = ureg_DECL_system_value(ureg, TGSI_SEMANTIC_INSTANCEID, 0); - - if (!st->pbo_upload.use_gs) - out_layer = ureg_DECL_output(ureg, TGSI_SEMANTIC_LAYER, 0); - } - - /* out_pos = in_pos */ - ureg_MOV(ureg, out_pos, in_pos); - - if (st->pbo_upload.upload_layers) { - if (st->pbo_upload.use_gs) { - /* out_pos.z = i2f(gl_InstanceID) */ - ureg_I2F(ureg, ureg_writemask(out_pos, TGSI_WRITEMASK_Z), - ureg_scalar(in_instanceid, TGSI_SWIZZLE_X)); - } else { - /* out_layer = gl_InstanceID */ - ureg_MOV(ureg, out_layer, in_instanceid); - } - } - - ureg_END(ureg); - - return ureg_create_shader_and_destroy(ureg, st->pipe); -} - -static void * -create_pbo_upload_gs(struct st_context *st) -{ - static const int zero = 0; - struct ureg_program *ureg; - struct ureg_dst out_pos; - struct ureg_dst out_layer; - struct ureg_src in_pos; - struct ureg_src imm; - unsigned i; - - ureg = ureg_create(TGSI_PROCESSOR_GEOMETRY); - if (!ureg) - return NULL; - - ureg_property(ureg, TGSI_PROPERTY_GS_INPUT_PRIM, PIPE_PRIM_TRIANGLES); - ureg_property(ureg, TGSI_PROPERTY_GS_OUTPUT_PRIM, PIPE_PRIM_TRIANGLE_STRIP); - ureg_property(ureg, TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES, 3); - - out_pos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); - out_layer = ureg_DECL_output(ureg, TGSI_SEMANTIC_LAYER, 0); - - in_pos = ureg_DECL_input(ureg, TGSI_SEMANTIC_POSITION, 0, 0, 1); - - imm = ureg_DECL_immediate_int(ureg, &zero, 1); - - for (i = 0; i < 3; ++i) { - struct ureg_src in_pos_vertex = ureg_src_dimension(in_pos, i); - - /* out_pos = in_pos[i] */ - ureg_MOV(ureg, out_pos, in_pos_vertex); - - /* out_layer.x = f2i(in_pos[i].z) */ - ureg_F2I(ureg, ureg_writemask(out_layer, TGSI_WRITEMASK_X), - ureg_scalar(in_pos_vertex, TGSI_SWIZZLE_Z)); - - ureg_EMIT(ureg, ureg_scalar(imm, TGSI_SWIZZLE_X)); - } - - ureg_END(ureg); - - return ureg_create_shader_and_destroy(ureg, st->pipe); -} - -static void * -create_pbo_upload_fs(struct st_context *st) -{ - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; - struct ureg_program *ureg; - struct ureg_dst out; - struct ureg_src sampler; - struct ureg_src pos; - struct ureg_src layer; - struct ureg_src const0; - struct ureg_dst temp0; - - ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); - if (!ureg) - return NULL; - - out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); - sampler = ureg_DECL_sampler(ureg, 0); - if (screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL)) { - pos = ureg_DECL_system_value(ureg, TGSI_SEMANTIC_POSITION, 0); - } else { - pos = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, 0, - TGSI_INTERPOLATE_LINEAR); - } - if (st->pbo_upload.upload_layers) { - layer = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_LAYER, 0, - TGSI_INTERPOLATE_CONSTANT); - } - const0 = ureg_DECL_constant(ureg, 0); - temp0 = ureg_DECL_temporary(ureg); - - /* Note: const0 = [ -xoffset + skip_pixels, -yoffset, stride, image_height ] */ - - /* temp0.xy = f2i(temp0.xy) */ - ureg_F2I(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY), - ureg_swizzle(pos, - TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, - TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y)); - - /* temp0.xy = temp0.xy + const0.xy */ - ureg_UADD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY), - ureg_swizzle(ureg_src(temp0), - TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, - TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y), - ureg_swizzle(const0, - TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, - TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y)); - - /* temp0.x = const0.z * temp0.y + temp0.x */ - ureg_UMAD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_X), - ureg_scalar(const0, TGSI_SWIZZLE_Z), - ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_Y), - ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_X)); - - if (st->pbo_upload.upload_layers) { - /* temp0.x = const0.w * layer + temp0.x */ - ureg_UMAD(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_X), - ureg_scalar(const0, TGSI_SWIZZLE_W), - ureg_scalar(layer, TGSI_SWIZZLE_X), - ureg_scalar(ureg_src(temp0), TGSI_SWIZZLE_X)); - } - - /* temp0.w = 0 */ - ureg_MOV(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_W), ureg_imm1u(ureg, 0)); - - /* out = txf(sampler, temp0.x) */ - ureg_TXF(ureg, out, TGSI_TEXTURE_BUFFER, ureg_src(temp0), sampler); - - ureg_release_temporary(ureg, temp0); - - ureg_END(ureg); - - return ureg_create_shader_and_destroy(ureg, pipe); -} - static bool try_pbo_upload_common(struct gl_context *ctx, struct pipe_surface *surface, - int xoffset, int yoffset, - unsigned upload_width, unsigned upload_height, - struct pipe_resource *buffer, - enum pipe_format src_format, - intptr_t buf_offset, - unsigned bytes_per_pixel, - unsigned stride, - unsigned image_height) + const struct st_pbo_addresses *addr, + enum pipe_format src_format) { struct st_context *st = st_context(ctx); struct cso_context *cso = st->cso_context; struct pipe_context *pipe = st->pipe; - unsigned depth = surface->u.tex.last_layer - surface->u.tex.first_layer + 1; - unsigned skip_pixels = 0; bool success = false; + void *fs; - /* Check alignment. */ - { - unsigned ofs = (buf_offset * bytes_per_pixel) % ctx->Const.TextureBufferOffsetAlignment; - if (ofs != 0) { - if (ofs % bytes_per_pixel != 0) - return false; - - skip_pixels = ofs / bytes_per_pixel; - buf_offset -= skip_pixels; - } - } - - /* Create the shaders */ - if (!st->pbo_upload.vs) { - st->pbo_upload.vs = create_pbo_upload_vs(st); - if (!st->pbo_upload.vs) - return false; - } - - if (depth != 1 && st->pbo_upload.use_gs && !st->pbo_upload.gs) { - st->pbo_upload.gs = create_pbo_upload_gs(st); - if (!st->pbo_upload.gs) - return false; - } - - if (!st->pbo_upload.fs) { - st->pbo_upload.fs = create_pbo_upload_fs(st); - if (!st->pbo_upload.fs) - return false; - } + fs = st_pbo_get_upload_fs(st, src_format, surface->format); + if (!fs) + return false; cso_save_state(cso, (CSO_BIT_FRAGMENT_SAMPLER_VIEWS | CSO_BIT_FRAGMENT_SAMPLERS | @@ -1346,37 +1161,35 @@ try_pbo_upload_common(struct gl_context *ctx, CSO_BIT_RASTERIZER | CSO_BIT_STREAM_OUTPUTS | CSO_BIT_PAUSE_QUERIES | + CSO_BIT_SAMPLE_MASK | + CSO_BIT_MIN_SAMPLES | + CSO_BIT_RENDER_CONDITION | CSO_BITS_ALL_SHADERS)); cso_save_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT); + cso_set_sample_mask(cso, ~0); + cso_set_min_samples(cso, 1); + cso_set_render_condition(cso, NULL, FALSE, 0); /* Set up the sampler_view */ { - unsigned first_element = buf_offset; - unsigned last_element = buf_offset + skip_pixels + upload_width - 1 - + (upload_height - 1 + (depth - 1) * image_height) * stride; struct pipe_sampler_view templ; struct pipe_sampler_view *sampler_view; struct pipe_sampler_state sampler = {0}; const struct pipe_sampler_state *samplers[1] = {&sampler}; - /* This should be ensured by Mesa before calling our callbacks */ - assert((last_element + 1) * bytes_per_pixel <= buffer->width0); - - if (last_element - first_element > ctx->Const.MaxTextureBufferSize - 1) - goto fail; - memset(&templ, 0, sizeof(templ)); templ.target = PIPE_BUFFER; templ.format = src_format; - templ.u.buf.first_element = first_element; - templ.u.buf.last_element = last_element; - templ.swizzle_r = PIPE_SWIZZLE_RED; - templ.swizzle_g = PIPE_SWIZZLE_GREEN; - templ.swizzle_b = PIPE_SWIZZLE_BLUE; - templ.swizzle_a = PIPE_SWIZZLE_ALPHA; - - sampler_view = pipe->create_sampler_view(pipe, buffer, &templ); + templ.u.buf.offset = addr->first_element * addr->bytes_per_pixel; + templ.u.buf.size = (addr->last_element - addr->first_element + 1) * + addr->bytes_per_pixel; + templ.swizzle_r = PIPE_SWIZZLE_X; + templ.swizzle_g = PIPE_SWIZZLE_Y; + templ.swizzle_b = PIPE_SWIZZLE_Z; + templ.swizzle_a = PIPE_SWIZZLE_W; + + sampler_view = pipe->create_sampler_view(pipe, addr->buffer, &templ); if (sampler_view == NULL) goto fail; @@ -1387,89 +1200,6 @@ try_pbo_upload_common(struct gl_context *ctx, cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, samplers); } - /* Upload vertices */ - { - struct pipe_vertex_buffer vbo; - struct pipe_vertex_element velem; - - float x0 = (float) xoffset / surface->width * 2.0f - 1.0f; - float y0 = (float) yoffset / surface->height * 2.0f - 1.0f; - float x1 = (float) (xoffset + upload_width) / surface->width * 2.0f - 1.0f; - float y1 = (float) (yoffset + upload_height) / surface->height * 2.0f - 1.0f; - - float *verts = NULL; - - vbo.user_buffer = NULL; - vbo.buffer = NULL; - vbo.stride = 2 * sizeof(float); - - u_upload_alloc(st->uploader, 0, 8 * sizeof(float), 4, - &vbo.buffer_offset, &vbo.buffer, (void **) &verts); - if (!verts) - goto fail; - - verts[0] = x0; - verts[1] = y0; - verts[2] = x0; - verts[3] = y1; - verts[4] = x1; - verts[5] = y0; - verts[6] = x1; - verts[7] = y1; - - u_upload_unmap(st->uploader); - - velem.src_offset = 0; - velem.instance_divisor = 0; - velem.vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso); - velem.src_format = PIPE_FORMAT_R32G32_FLOAT; - - cso_set_vertex_elements(cso, 1, &velem); - - cso_set_vertex_buffers(cso, velem.vertex_buffer_index, 1, &vbo); - - pipe_resource_reference(&vbo.buffer, NULL); - } - - /* Upload constants */ - /* Note: the user buffer must be valid until draw time */ - struct { - int32_t xoffset; - int32_t yoffset; - int32_t stride; - int32_t image_size; - } constants; - - { - struct pipe_constant_buffer cb; - - constants.xoffset = -xoffset + skip_pixels; - constants.yoffset = -yoffset; - constants.stride = stride; - constants.image_size = stride * image_height; - - if (st->constbuf_uploader) { - cb.buffer = NULL; - cb.user_buffer = NULL; - u_upload_data(st->constbuf_uploader, 0, sizeof(constants), - ctx->Const.UniformBufferOffsetAlignment, - &constants, &cb.buffer_offset, &cb.buffer); - if (!cb.buffer) - goto fail; - - u_upload_unmap(st->constbuf_uploader); - } else { - cb.buffer = NULL; - cb.user_buffer = &constants; - cb.buffer_offset = 0; - } - cb.buffer_size = sizeof(constants); - - cso_set_constant_buffer(cso, PIPE_SHADER_FRAGMENT, 0, &cb); - - pipe_resource_reference(&cb.buffer, NULL); - } - /* Framebuffer_state */ { struct pipe_framebuffer_state fb; @@ -1487,7 +1217,7 @@ try_pbo_upload_common(struct gl_context *ctx, cso_set_viewport_dims(cso, surface->width, surface->height, FALSE); /* Blend state */ - cso_set_blend(cso, &st->pbo_upload.blend); + cso_set_blend(cso, &st->pbo.upload_blend); /* Depth/stencil/alpha state */ { @@ -1496,31 +1226,10 @@ try_pbo_upload_common(struct gl_context *ctx, cso_set_depth_stencil_alpha(cso, &dsa); } - /* Rasterizer state */ - cso_set_rasterizer(cso, &st->pbo_upload.raster); - - /* Set up the shaders */ - cso_set_vertex_shader_handle(cso, st->pbo_upload.vs); - - cso_set_geometry_shader_handle(cso, depth != 1 ? st->pbo_upload.gs : NULL); - - cso_set_tessctrl_shader_handle(cso, NULL); - - cso_set_tesseval_shader_handle(cso, NULL); + /* Set up the fragment shader */ + cso_set_fragment_shader_handle(cso, fs); - cso_set_fragment_shader_handle(cso, st->pbo_upload.fs); - - /* Disable stream output */ - cso_set_stream_outputs(cso, 0, NULL, 0); - - if (depth == 1) { - cso_draw_arrays(cso, PIPE_PRIM_TRIANGLE_STRIP, 0, 4); - } else { - cso_draw_arrays_instanced(cso, PIPE_PRIM_TRIANGLE_STRIP, - 0, 4, 0, depth); - } - - success = true; + success = st_pbo_draw(st, addr, surface->width, surface->height); fail: cso_restore_state(cso); @@ -1546,15 +1255,13 @@ try_pbo_upload(struct gl_context *ctx, GLuint dims, struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct pipe_surface *surface = NULL; + struct st_pbo_addresses addr; enum pipe_format src_format; const struct util_format_description *desc; GLenum gl_target = texImage->TexObject->Target; - intptr_t buf_offset; - unsigned bytes_per_pixel; - unsigned stride, image_height; bool success; - if (!st->pbo_upload.enabled) + if (!st->pbo.upload_enabled) return false; /* From now on, we need the gallium representation of dimensions. */ @@ -1563,12 +1270,9 @@ try_pbo_upload(struct gl_context *ctx, GLuint dims, height = 1; zoffset = yoffset; yoffset = 0; - image_height = 1; - } else { - image_height = unpack->ImageHeight > 0 ? unpack->ImageHeight : height; } - if (depth != 1 && !st->pbo_upload.upload_layers) + if (depth != 1 && !st->pbo.layers) return false; /* Choose the source format. Initially, we do so without checking driver @@ -1589,7 +1293,7 @@ try_pbo_upload(struct gl_context *ctx, GLuint dims, if (desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB) return false; - if (st->pbo_upload.rgba_only) { + if (st->pbo.rgba_only) { enum pipe_format orig_dst_format = dst_format; if (!reinterpret_formats(&src_format, &dst_format)) { @@ -1609,40 +1313,17 @@ try_pbo_upload(struct gl_context *ctx, GLuint dims, return false; } - /* Check if the offset satisfies the alignment requirements */ - buf_offset = (intptr_t) pixels; - bytes_per_pixel = desc->block.bits / 8; + /* Compute buffer addresses */ + addr.xoffset = xoffset; + addr.yoffset = yoffset; + addr.width = width; + addr.height = height; + addr.depth = depth; + addr.bytes_per_pixel = desc->block.bits / 8; - if (buf_offset % bytes_per_pixel) { + if (!st_pbo_addresses_pixelstore(st, gl_target, dims == 3, unpack, pixels, + &addr)) return false; - } - - /* Convert to texels */ - buf_offset = buf_offset / bytes_per_pixel; - - /* Compute the stride, taking unpack->Alignment into account */ - { - unsigned pixels_per_row = unpack->RowLength > 0 ? - unpack->RowLength : width; - unsigned bytes_per_row = pixels_per_row * bytes_per_pixel; - unsigned remainder = bytes_per_row % unpack->Alignment; - unsigned offset_rows; - - if (remainder > 0) - bytes_per_row += (unpack->Alignment - remainder); - - if (bytes_per_row % bytes_per_pixel) { - return false; - } - - stride = bytes_per_row / bytes_per_pixel; - - offset_rows = unpack->SkipRows; - if (dims == 3) - offset_rows += image_height * unpack->SkipImages; - - buf_offset += unpack->SkipPixels + stride * offset_rows; - } /* Set up the surface */ { @@ -1663,12 +1344,7 @@ try_pbo_upload(struct gl_context *ctx, GLuint dims, return false; } - success = try_pbo_upload_common(ctx, surface, - xoffset, yoffset, width, height, - st_buffer_object(unpack->BufferObj)->buffer, - src_format, - buf_offset, - bytes_per_pixel, stride, image_height); + success = try_pbo_upload_common(ctx, surface, &addr, src_format); pipe_surface_reference(&surface, NULL); @@ -1698,15 +1374,53 @@ st_TexSubImage(struct gl_context *ctx, GLuint dims, GLenum gl_target = texImage->TexObject->Target; unsigned bind; GLubyte *map; + unsigned dstz = texImage->Face + texImage->TexObject->MinLayer; + unsigned dst_level = 0; + + st_flush_bitmap_cache(st); + st_invalidate_readpix_cache(st); + + if (stObj->pt == stImage->pt) + dst_level = texImage->TexObject->MinLevel + texImage->Level; assert(!_mesa_is_format_etc2(texImage->TexFormat) && texImage->TexFormat != MESA_FORMAT_ETC1_RGB8); - if (!st->prefer_blit_based_texture_transfer) { + if (!dst) goto fallback; + + /* Try texture_subdata, which should be the fastest memcpy path. */ + if (pixels && + !_mesa_is_bufferobj(unpack->BufferObj) && + _mesa_texstore_can_use_memcpy(ctx, texImage->_BaseFormat, + texImage->TexFormat, format, type, + unpack)) { + struct pipe_box box; + unsigned stride, layer_stride; + void *data; + + stride = _mesa_image_row_stride(unpack, width, format, type); + layer_stride = _mesa_image_image_stride(unpack, width, height, format, + type); + data = _mesa_image_address(dims, unpack, pixels, width, height, format, + type, 0, 0, 0); + + /* Convert to Gallium coordinates. */ + if (gl_target == GL_TEXTURE_1D_ARRAY) { + zoffset = yoffset; + yoffset = 0; + depth = height; + height = 1; + layer_stride = stride; + } + + u_box_3d(xoffset, yoffset, zoffset + dstz, width, height, depth, &box); + pipe->texture_subdata(pipe, dst, dst_level, 0, + &box, data, stride, layer_stride); + return; } - if (!dst) { + if (!st->prefer_blit_based_texture_transfer) { goto fallback; } @@ -1875,12 +1589,12 @@ st_TexSubImage(struct gl_context *ctx, GLuint dims, blit.src.level = 0; blit.src.format = src_format; blit.dst.resource = dst; - blit.dst.level = stObj->pt != stImage->pt ? 0 : texImage->TexObject->MinLevel + texImage->Level; + blit.dst.level = dst_level; blit.dst.format = dst_format; blit.src.box.x = blit.src.box.y = blit.src.box.z = 0; blit.dst.box.x = xoffset; blit.dst.box.y = yoffset; - blit.dst.box.z = zoffset + texImage->Face + texImage->TexObject->MinLayer; + blit.dst.box.z = zoffset + dstz; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = depth; @@ -1940,8 +1654,8 @@ st_CompressedTexSubImage(struct gl_context *ctx, GLuint dims, struct pipe_resource *dst = stImage->pt; struct pipe_surface *surface = NULL; struct compressed_pixelstore store; + struct st_pbo_addresses addr; enum pipe_format copy_format; - unsigned bytes_per_block; unsigned bw, bh; intptr_t buf_offset; bool success = false; @@ -1954,8 +1668,7 @@ st_CompressedTexSubImage(struct gl_context *ctx, GLuint dims, if (!_mesa_is_bufferobj(ctx->Unpack.BufferObj)) goto fallback; - if ((_mesa_is_format_etc2(texImage->TexFormat) && !st->has_etc2) || - (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8 && !st->has_etc1)) { + if (st_etc_fallback(st, texImage)) { /* ETC isn't supported and is represented by uncompressed formats. */ goto fallback; } @@ -1964,17 +1677,17 @@ st_CompressedTexSubImage(struct gl_context *ctx, GLuint dims, goto fallback; } - if (!st->pbo_upload.enabled || + if (!st->pbo.upload_enabled || !screen->get_param(screen, PIPE_CAP_SURFACE_REINTERPRET_BLOCKS)) { goto fallback; } /* Choose the pipe format for the upload. */ - bytes_per_block = util_format_get_blocksize(dst->format); + addr.bytes_per_pixel = util_format_get_blocksize(dst->format); bw = util_format_get_blockwidth(dst->format); bh = util_format_get_blockheight(dst->format); - switch (bytes_per_block) { + switch (addr.bytes_per_pixel) { case 8: copy_format = PIPE_FORMAT_R16G16B16A16_UINT; break; @@ -1998,17 +1711,29 @@ st_CompressedTexSubImage(struct gl_context *ctx, GLuint dims, /* Interpret the pixelstore settings. */ _mesa_compute_compressed_pixelstore(dims, texImage->TexFormat, w, h, d, &ctx->Unpack, &store); - assert(store.CopyBytesPerRow % bytes_per_block == 0); - assert(store.SkipBytes % bytes_per_block == 0); + assert(store.CopyBytesPerRow % addr.bytes_per_pixel == 0); + assert(store.SkipBytes % addr.bytes_per_pixel == 0); /* Compute the offset into the buffer */ buf_offset = (intptr_t)data + store.SkipBytes; - if (buf_offset % bytes_per_block) { + if (buf_offset % addr.bytes_per_pixel) { goto fallback; } - buf_offset = buf_offset / bytes_per_block; + buf_offset = buf_offset / addr.bytes_per_pixel; + + addr.xoffset = x / bw; + addr.yoffset = y / bh; + addr.width = store.CopyBytesPerRow / addr.bytes_per_pixel; + addr.height = store.CopyRowsPerSlice; + addr.depth = d; + addr.pixels_per_row = store.TotalBytesPerRow / addr.bytes_per_pixel; + addr.image_height = store.TotalRowsPerSlice; + + if (!st_pbo_addresses_setup(st, st_buffer_object(ctx->Unpack.BufferObj)->buffer, + buf_offset, &addr)) + goto fallback; /* Set up the surface. */ { @@ -2029,16 +1754,7 @@ st_CompressedTexSubImage(struct gl_context *ctx, GLuint dims, goto fallback; } - success = try_pbo_upload_common(ctx, surface, - x / bw, y / bh, - store.CopyBytesPerRow / bytes_per_block, - store.CopyRowsPerSlice, - st_buffer_object(ctx->Unpack.BufferObj)->buffer, - copy_format, - buf_offset, - bytes_per_block, - store.TotalBytesPerRow / bytes_per_block, - store.TotalRowsPerSlice); + success = try_pbo_upload_common(ctx, surface, &addr, copy_format); pipe_surface_reference(&surface, NULL); @@ -2122,8 +1838,9 @@ st_GetTexSubImage(struct gl_context * ctx, mesa_format mesa_format; GLenum gl_target = texImage->TexObject->Target; enum pipe_texture_target pipe_target; + unsigned dims; struct pipe_blit_info blit; - unsigned bind = PIPE_BIND_TRANSFER_READ; + unsigned bind; struct pipe_transfer *tex_xfer; ubyte *map = NULL; boolean done = FALSE; @@ -2131,13 +1848,16 @@ st_GetTexSubImage(struct gl_context * ctx, assert(!_mesa_is_format_etc2(texImage->TexFormat) && texImage->TexFormat != MESA_FORMAT_ETC1_RGB8); + st_flush_bitmap_cache(st); + if (!st->prefer_blit_based_texture_transfer && !_mesa_is_format_compressed(texImage->TexFormat)) { /* Try to avoid the fallback if we're doing texture decompression here */ goto fallback; } - if (!stImage->pt || !src) { + /* Handle non-finalized textures. */ + if (!stImage->pt || stImage->pt != stObj->pt || !src) { goto fallback; } @@ -2184,9 +1904,9 @@ st_GetTexSubImage(struct gl_context * ctx, } if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL) - bind |= PIPE_BIND_DEPTH_STENCIL; + bind = PIPE_BIND_DEPTH_STENCIL; else - bind |= PIPE_BIND_RENDER_TARGET; + bind = PIPE_BIND_RENDER_TARGET; /* GetTexImage only returns a single face for cubemaps. */ if (gl_target == GL_TEXTURE_CUBE_MAP) { @@ -2307,6 +2027,7 @@ st_GetTexSubImage(struct gl_context * ctx, } mesa_format = st_pipe_format_to_mesa_format(dst_format); + dims = _mesa_get_texture_dimensions(gl_target); /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(mesa_format, format, type, @@ -2316,39 +2037,31 @@ st_GetTexSubImage(struct gl_context * ctx, GLuint row, slice; for (slice = 0; slice < depth; slice++) { - if (gl_target == GL_TEXTURE_1D_ARRAY) { - /* 1D array textures. - * We need to convert gallium coords to GL coords. - */ - void *dest = _mesa_image_address3d(&ctx->Pack, pixels, - width, depth, format, - type, 0, slice, 0); - memcpy(dest, map, bytesPerRow); - } - else { - ubyte *slice_map = map; + ubyte *slice_map = map; - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address3d(&ctx->Pack, pixels, - width, height, format, - type, slice, row, 0); - memcpy(dest, slice_map, bytesPerRow); - slice_map += tex_xfer->stride; - } + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dims, &ctx->Pack, pixels, + width, height, format, type, + slice, row, 0); + + memcpy(dest, slice_map, bytesPerRow); + + slice_map += tex_xfer->stride; } + map += tex_xfer->layer_stride; } } else { /* format translation via floats */ - GLuint row, slice; + GLuint slice; GLfloat *rgba; uint32_t dstMesaFormat; int dstStride, srcStride; assert(util_format_is_compressed(src->format)); - rgba = malloc(width * 4 * sizeof(GLfloat)); + rgba = malloc(width * height * 4 * sizeof(GLfloat)); if (!rgba) { goto end; } @@ -2360,37 +2073,24 @@ st_GetTexSubImage(struct gl_context * ctx, dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type); srcStride = 4 * width * sizeof(GLfloat); for (slice = 0; slice < depth; slice++) { - if (gl_target == GL_TEXTURE_1D_ARRAY) { - /* 1D array textures. - * We need to convert gallium coords to GL coords. - */ - void *dest = _mesa_image_address3d(&ctx->Pack, pixels, - width, depth, format, - type, 0, slice, 0); - - /* get float[4] rgba row from surface */ - pipe_get_tile_rgba_format(tex_xfer, map, 0, 0, width, 1, - dst_format, rgba); - - _mesa_format_convert(dest, dstMesaFormat, dstStride, - rgba, RGBA32_FLOAT, srcStride, - width, 1, NULL); - } - else { - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address3d(&ctx->Pack, pixels, - width, height, format, - type, slice, row, 0); - - /* get float[4] rgba row from surface */ - pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1, - dst_format, rgba); - - _mesa_format_convert(dest, dstMesaFormat, dstStride, - rgba, RGBA32_FLOAT, srcStride, - width, 1, NULL); - } + void *dest = _mesa_image_address(dims, &ctx->Pack, pixels, + width, height, format, type, + slice, 0, 0); + + /* get float[4] rgba row from surface */ + pipe_get_tile_rgba_format(tex_xfer, map, 0, 0, width, height, + dst_format, rgba); + + _mesa_format_convert(dest, dstMesaFormat, dstStride, + rgba, RGBA32_FLOAT, srcStride, + width, height, NULL); + + /* Handle byte swapping if required */ + if (ctx->Pack.SwapBytes) { + _mesa_swap_bytes_2d_image(format, type, &ctx->Pack, + width, height, dest, dest); } + map += tex_xfer->layer_stride; } @@ -2593,6 +2293,9 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims, unsigned bind; GLint srcY0, srcY1; + st_flush_bitmap_cache(st); + st_invalidate_readpix_cache(st); + assert(!_mesa_is_format_etc2(texImage->TexFormat) && texImage->TexFormat != MESA_FORMAT_ETC1_RGB8); @@ -2737,7 +2440,8 @@ copy_image_data_to_texture(struct st_context *st, GLboolean st_finalize_texture(struct gl_context *ctx, struct pipe_context *pipe, - struct gl_texture_object *tObj) + struct gl_texture_object *tObj, + GLuint cubeMapFace) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(tObj); @@ -2745,7 +2449,8 @@ st_finalize_texture(struct gl_context *ctx, GLuint face; const struct st_texture_image *firstImage; enum pipe_format firstImageFormat; - GLuint ptWidth, ptHeight, ptDepth, ptLayers, ptNumSamples; + unsigned ptWidth; + uint16_t ptHeight, ptDepth, ptLayers, ptNumSamples; if (tObj->Immutable) return GL_TRUE; @@ -2764,29 +2469,19 @@ st_finalize_texture(struct gl_context *ctx, stObj->lastLevel = stObj->base._MaxLevel; } - if (tObj->Target == GL_TEXTURE_BUFFER) { - struct st_buffer_object *st_obj = st_buffer_object(tObj->BufferObject); - - if (!st_obj) { - pipe_resource_reference(&stObj->pt, NULL); - st_texture_release_all_sampler_views(st, stObj); - return GL_TRUE; - } + firstImage = st_texture_image_const(stObj->base.Image[cubeMapFace][stObj->base.BaseLevel]); + assert(firstImage); - if (st_obj->buffer != stObj->pt) { - pipe_resource_reference(&stObj->pt, st_obj->buffer); - st_texture_release_all_sampler_views(st, stObj); - stObj->width0 = stObj->pt->width0 / _mesa_get_format_bytes(tObj->_BufferObjectFormat); - stObj->height0 = 1; - stObj->depth0 = 1; - } + /* Skip the loop over images in the common case of no images having + * changed. But if the GL_BASE_LEVEL or GL_MAX_LEVEL change to something we + * haven't looked at, then we do need to look at those new images. + */ + if (!stObj->needs_validation && + stObj->base.BaseLevel >= stObj->validated_first_level && + stObj->lastLevel <= stObj->validated_last_level) { return GL_TRUE; - } - firstImage = st_texture_image_const(_mesa_base_tex_image(&stObj->base)); - assert(firstImage); - /* If both firstImage and stObj point to a texture which can contain * all active images, favour firstImage. Note that because of the * completeness requirement, we know that the image dimensions @@ -2810,26 +2505,58 @@ st_finalize_texture(struct gl_context *ctx, /* Find size of level=0 Gallium mipmap image, plus number of texture layers */ { - GLuint width, height, depth; - if (!guess_base_level_size(stObj->base.Target, - firstImage->base.Width2, - firstImage->base.Height2, - firstImage->base.Depth2, - firstImage->base.Level, - &width, &height, &depth)) { - width = stObj->width0; - height = stObj->height0; - depth = stObj->depth0; + unsigned width; + uint16_t height, depth; + + st_gl_texture_dims_to_pipe_dims(stObj->base.Target, + firstImage->base.Width2, + firstImage->base.Height2, + firstImage->base.Depth2, + &width, &height, &depth, &ptLayers); + + /* If we previously allocated a pipe texture and its sizes are + * compatible, use them. + */ + if (stObj->pt && + u_minify(stObj->pt->width0, firstImage->base.Level) == width && + u_minify(stObj->pt->height0, firstImage->base.Level) == height && + u_minify(stObj->pt->depth0, firstImage->base.Level) == depth) { + ptWidth = stObj->pt->width0; + ptHeight = stObj->pt->height0; + ptDepth = stObj->pt->depth0; } else { - /* The width/height/depth may have been previously reset in - * guess_and_alloc_texture. */ - stObj->width0 = width; - stObj->height0 = height; - stObj->depth0 = depth; + /* Otherwise, compute a new level=0 size that is compatible with the + * base level image. + */ + ptWidth = width > 1 ? width << firstImage->base.Level : 1; + ptHeight = height > 1 ? height << firstImage->base.Level : 1; + ptDepth = depth > 1 ? depth << firstImage->base.Level : 1; + + /* If the base level image is 1x1x1, we still need to ensure that the + * resulting pipe texture ends up with the required number of levels + * in total. + */ + if (ptWidth == 1 && ptHeight == 1 && ptDepth == 1) { + ptWidth <<= firstImage->base.Level; + + if (stObj->base.Target == GL_TEXTURE_CUBE_MAP || + stObj->base.Target == GL_TEXTURE_CUBE_MAP_ARRAY) + ptHeight = ptWidth; + } + + /* At this point, the texture may be incomplete (mismatched cube + * face sizes, for example). If that's the case, give up, but + * don't return GL_FALSE as that would raise an incorrect + * GL_OUT_OF_MEMORY error. See Piglit fbo-incomplete-texture-03 test. + */ + if (!stObj->base._BaseComplete) { + _mesa_test_texobj_completeness(ctx, &stObj->base); + if (!stObj->base._BaseComplete) { + return TRUE; + } + } } - /* convert GL dims to Gallium dims */ - st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, - &ptWidth, &ptHeight, &ptDepth, &ptLayers); + ptNumSamples = firstImage->base.NumSamples; } @@ -2851,7 +2578,7 @@ st_finalize_texture(struct gl_context *ctx, */ pipe_resource_reference(&stObj->pt, NULL); st_texture_release_all_sampler_views(st, stObj); - st->dirty.st |= ST_NEW_FRAMEBUFFER; + st->dirty |= ST_NEW_FRAMEBUFFER; } } @@ -2887,16 +2614,23 @@ st_finalize_texture(struct gl_context *ctx, /* Need to import images in main memory or held in other textures. */ if (stImage && stObj->pt != stImage->pt) { - GLuint height = stObj->height0; - GLuint depth = stObj->depth0; + GLuint height; + GLuint depth; if (stObj->base.Target != GL_TEXTURE_1D_ARRAY) - height = u_minify(height, level); + height = u_minify(ptHeight, level); + else + height = ptLayers; + if (stObj->base.Target == GL_TEXTURE_3D) - depth = u_minify(depth, level); + depth = u_minify(ptDepth, level); + else if (stObj->base.Target == GL_TEXTURE_CUBE_MAP) + depth = 1; + else + depth = ptLayers; if (level == 0 || - (stImage->base.Width == u_minify(stObj->width0, level) && + (stImage->base.Width == u_minify(ptWidth, level) && stImage->base.Height == height && stImage->base.Depth == depth)) { /* src image fits expected dest mipmap level size */ @@ -2906,6 +2640,10 @@ st_finalize_texture(struct gl_context *ctx, } } + stObj->validated_first_level = stObj->base.BaseLevel; + stObj->validated_last_level = stObj->lastLevel; + stObj->needs_validation = false; + return GL_TRUE; } @@ -2925,17 +2663,14 @@ st_AllocTextureStorage(struct gl_context *ctx, struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct pipe_screen *screen = st->pipe->screen; - GLuint ptWidth, ptHeight, ptDepth, ptLayers, bindings; + unsigned ptWidth, bindings; + uint16_t ptHeight, ptDepth, ptLayers; enum pipe_format fmt; GLint level; GLuint num_samples = texImage->NumSamples; assert(levels > 0); - /* Save the level=0 dimensions */ - stObj->width0 = width; - stObj->height0 = height; - stObj->depth0 = depth; stObj->lastLevel = levels - 1; fmt = st_mesa_format_to_pipe_format(st, texImage->TexFormat); @@ -2985,18 +2720,25 @@ st_AllocTextureStorage(struct gl_context *ctx, struct st_texture_image *stImage = st_texture_image(texObj->Image[face][level]); pipe_resource_reference(&stImage->pt, stObj->pt); + + etc_fallback_allocate(st, stImage); } } + /* The texture is in a validated state, so no need to check later. */ + stObj->needs_validation = false; + stObj->validated_first_level = 0; + stObj->validated_last_level = levels - 1; + return GL_TRUE; } static GLboolean st_TestProxyTexImage(struct gl_context *ctx, GLenum target, - GLint level, mesa_format format, - GLint width, GLint height, - GLint depth, GLint border) + GLuint numLevels, GLint level, + mesa_format format, GLuint numSamples, + GLint width, GLint height, GLint depth) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; @@ -3018,14 +2760,19 @@ st_TestProxyTexImage(struct gl_context *ctx, GLenum target, pt.target = gl_target_to_pipe(target); pt.format = st_mesa_format_to_pipe_format(st, format); + pt.nr_samples = numSamples; st_gl_texture_dims_to_pipe_dims(target, width, height, depth, &pt.width0, &pt.height0, &pt.depth0, &pt.array_size); - if (level == 0 && (texObj->Sampler.MinFilter == GL_LINEAR || - texObj->Sampler.MinFilter == GL_NEAREST)) { + if (numLevels > 0) { + /* For immutable textures we know the final number of mip levels */ + pt.last_level = numLevels - 1; + } + else if (level == 0 && (texObj->Sampler.MinFilter == GL_LINEAR || + texObj->Sampler.MinFilter == GL_NEAREST)) { /* assume just one mipmap level */ pt.last_level = 0; } @@ -3038,8 +2785,8 @@ st_TestProxyTexImage(struct gl_context *ctx, GLenum target, } else { /* Use core Mesa fallback */ - return _mesa_test_proxy_teximage(ctx, target, level, format, - width, height, depth, border); + return _mesa_test_proxy_teximage(ctx, target, numLevels, level, format, + numSamples, width, height, depth); } } @@ -3048,6 +2795,7 @@ st_TextureView(struct gl_context *ctx, struct gl_texture_object *texObj, struct gl_texture_object *origTexObj) { + struct st_context *st = st_context(ctx); struct st_texture_object *orig = st_texture_object(origTexObj); struct st_texture_object *tex = st_texture_object(texObj); struct gl_texture_image *image = texObj->Image[0][0]; @@ -3073,11 +2821,18 @@ st_TextureView(struct gl_context *ctx, tex->surface_format = st_mesa_format_to_pipe_format(st_context(ctx), image->TexFormat); - tex->width0 = image->Width; - tex->height0 = image->Height; - tex->depth0 = image->Depth; tex->lastLevel = numLevels - 1; + /* free texture sampler views. They need to be recreated when we + * change the texture view parameters. + */ + st_texture_release_all_sampler_views(st, tex); + + /* The texture is in a validated state, so no need to check later. */ + tex->needs_validation = false; + tex->validated_first_level = 0; + tex->validated_last_level = numLevels - 1; + return GL_TRUE; } @@ -3099,6 +2854,9 @@ st_ClearTexSubImage(struct gl_context *ctx, if (!pt) return; + st_flush_bitmap_cache(st); + st_invalidate_readpix_cache(st); + u_box_3d(xoffset, yoffset, zoffset + texImage->Face, width, height, depth, &box); if (texImage->TexObject->Immutable) { @@ -3109,6 +2867,121 @@ st_ClearTexSubImage(struct gl_context *ctx, pipe->clear_texture(pipe, pt, level, &box, clearValue ? clearValue : zeros); } + +/** + * Called via the glTexParam*() function, but only when some texture object + * state has actually changed. + */ +static void +st_TexParameter(struct gl_context *ctx, + struct gl_texture_object *texObj, GLenum pname) +{ + struct st_context *st = st_context(ctx); + struct st_texture_object *stObj = st_texture_object(texObj); + + switch (pname) { + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_DEPTH_TEXTURE_MODE: + case GL_DEPTH_STENCIL_TEXTURE_MODE: + case GL_TEXTURE_SRGB_DECODE_EXT: + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + case GL_TEXTURE_SWIZZLE_RGBA: + case GL_TEXTURE_BUFFER_SIZE: + case GL_TEXTURE_BUFFER_OFFSET: + /* changing any of these texture parameters means we must create + * new sampler views. + */ + st_texture_release_all_sampler_views(st, stObj); + break; + default: + ; /* nothing */ + } +} + + +static GLuint64 +st_NewTextureHandle(struct gl_context *ctx, struct gl_texture_object *texObj, + struct gl_sampler_object *sampObj) +{ + struct st_context *st = st_context(ctx); + struct st_texture_object *stObj = st_texture_object(texObj); + struct pipe_context *pipe = st->pipe; + struct pipe_sampler_view *view; + struct pipe_sampler_state sampler = {0}; + + if (texObj->Target != GL_TEXTURE_BUFFER) { + if (!st_finalize_texture(ctx, pipe, texObj, 0)) + return 0; + + st_convert_sampler(st, texObj, sampObj, &sampler); + view = st_get_texture_sampler_view_from_stobj(st, stObj, sampObj, 0); + } else { + view = st_get_buffer_sampler_view_from_stobj(st, stObj); + } + + return pipe->create_texture_handle(pipe, view, &sampler); +} + + +static void +st_DeleteTextureHandle(struct gl_context *ctx, GLuint64 handle) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + + pipe->delete_texture_handle(pipe, handle); +} + + +static void +st_MakeTextureHandleResident(struct gl_context *ctx, GLuint64 handle, + bool resident) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + + pipe->make_texture_handle_resident(pipe, handle, resident); +} + + +static GLuint64 +st_NewImageHandle(struct gl_context *ctx, struct gl_image_unit *imgObj) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_image_view image; + + st_convert_image(st, imgObj, &image); + + return pipe->create_image_handle(pipe, &image); +} + + +static void +st_DeleteImageHandle(struct gl_context *ctx, GLuint64 handle) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + + pipe->delete_image_handle(pipe, handle); +} + + +static void +st_MakeImageHandleResident(struct gl_context *ctx, GLuint64 handle, + GLenum access, bool resident) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + + pipe->make_image_handle_resident(pipe, handle, access, resident); +} + + void st_init_texture_functions(struct dd_function_table *functions) { @@ -3141,4 +3014,14 @@ st_init_texture_functions(struct dd_function_table *functions) functions->AllocTextureStorage = st_AllocTextureStorage; functions->TextureView = st_TextureView; functions->ClearTexSubImage = st_ClearTexSubImage; + + functions->TexParameter = st_TexParameter; + + /* bindless functions */ + functions->NewTextureHandle = st_NewTextureHandle; + functions->DeleteTextureHandle = st_DeleteTextureHandle; + functions->MakeTextureHandleResident = st_MakeTextureHandleResident; + functions->NewImageHandle = st_NewImageHandle; + functions->DeleteImageHandle = st_DeleteImageHandle; + functions->MakeImageHandleResident = st_MakeImageHandleResident; }