Bug 59455 - Crash when using VBO drawing to selection buffer
Summary: Crash when using VBO drawing to selection buffer
Alias: None
Product: Mesa
Classification: Unclassified
Component: Drivers/DRI/i965 (show other bugs)
Version: 8.0
Hardware: Other All
: medium normal
Assignee: Ian Romanick
QA Contact:
: 61149 (view as bug list)
Depends on:
Reported: 2013-01-16 08:26 UTC by Sergey Sharybin
Modified: 2014-03-31 07:05 UTC (History)
3 users (show)

See Also:
i915 platform:
i915 features:

Crash backtrace (5.31 KB, text/plain)
2013-01-16 08:26 UTC, Sergey Sharybin
Patch (1.33 KB, patch)
2014-03-21 12:24 UTC, Iago Toral
Details | Splinter Review

Description Sergey Sharybin 2013-01-16 08:26:14 UTC
Created attachment 73139 [details]
Crash backtrace


Since some of 8.0.x update we're experiencing Blender crash on Intel cards when using VBO and trying to select objects.

The thing here is we're using selection buffer and seems as soon as VBO drawing happens to selection buffer crash happens inside of Mesa (backtrace is attached).

We do not believe it is Blender bug -- it never happens on other videocards/drivers (like software render mode on the same intel card. neuveau driver, nvidia proprietary driver), other operation systems also works fine in such situation. And if i remember correct, there was no crash with older mesa releases.

System specifications:
* Operation system is Debian Wheezy, amd64
* Mesa version is 8.0.5 (from Wheezy repository)
* Video card Intel Sandybridge Mobile (think it's HD3000, integrated card to Intel i5-2410M CPU)

Steps to reproduce:
* Get Blender archive from http://www.blender.org/download/get-blender/
* Unpack it and run
* In User Preferences go to System tab, enable VBO
* Close user preferences
* Try left-click on cube

Thanks for the help.
Comment 1 Antony Riakiotakis 2013-02-20 11:07:30 UTC
*** Bug 61149 has been marked as a duplicate of this bug. ***
Comment 2 Sinan Hassani 2013-02-20 17:26:01 UTC
Just some further notes regarding what I'm getting with Blender 2.65a and 2.66RC:

The bug doesn't happen by simply doing an initial 
select of an object in default scene, but rather when you select one 
object and then try to select another different object (the crashing 
happens), i.e. multi-selection.

My specs:

OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) Ivybridge Mobile 
OpenGL version string: 3.0 Mesa 9.2-devel
OpenGL shading language version string: 1.30

Using Intel HD Graphics 4000 graphics card.
Comment 3 Iago Toral 2014-03-18 07:53:22 UTC
I can reproduce this with Intel HD 4000 and Mesa from master (2c886eba7820f7e3e965dd16b786b0a412d8ef11).

I don't need to have two objects in the scene, simply enable VBO, then right-click on the cube (notice that I have to right-click to select an object in the scene, not left-click). Happens on every attempt.

Updated backtrace:

0x00007fffd9bdd1fd in run_vp (ctx=0x2e312f8, stage=0x2e96370) at tnl/t_vb_program.c:369
369		    COPY_CLEAN_4V(machine->VertAttribs[attr], size, data);
(gdb) bt
#0  0x00007fffd9bdd1fd in run_vp (ctx=0x2e312f8, stage=0x2e96370) at tnl/t_vb_program.c:369
#1  0x00007fffd9bd8b32 in _tnl_run_pipeline (ctx=0x2e312f8) at tnl/t_pipeline.c:163
#2  0x00007fffd9bda4e7 in _tnl_draw_prims (ctx=0x2e312f8, arrays=0x7ffffffd4ba0, prim=0x7ffffffd57d0, nr_prims=1, ib=0x7ffffffd4b80, min_index=0, max_index=0)
    at tnl/t_draw.c:529
#3  0x00007fffd9bda1a6 in _tnl_vbo_draw_prims (ctx=0x2e312f8, prim=0x7ffffffd57d0, nr_prims=1, ib=0x7ffffffd4b80, index_bounds_valid=1 '\001', min_index=0, max_index=0, 
    tfb_vertcount=0x0, indirect=0x0) at tnl/t_draw.c:429
#4  0x00007fffd9bb694d in vbo_rebase_prims (ctx=0x2e312f8, arrays=0x2e93450, prim=0x7ffffffd57d0, nr_prims=1, ib=0x7ffffffd4b80, min_index=4294967295, max_index=4294967295, 
    draw=0x7fffd9bda129 <_tnl_vbo_draw_prims>) at vbo/vbo_rebase.c:234
#5  0x00007fffd9bda2e0 in _tnl_draw_prims (ctx=0x2e312f8, arrays=0x2e93450, prim=0x7ffffffd57d0, nr_prims=1, ib=0x7ffffffd57b0, min_index=4294967295, max_index=4294967295)
    at tnl/t_draw.c:472
#6  0x00007fffd9dc7560 in brw_draw_prims (ctx=0x2e312f8, prims=0x7ffffffd57d0, nr_prims=1, ib=0x7ffffffd57b0, index_bounds_valid=0 '\000', min_index=4294967295, 
    max_index=4294967295, unused_tfb_object=0x0, indirect=0x0) at brw_draw.c:571
#7  0x00007fffd9bb019f in vbo_handle_primitive_restart (ctx=0x2e312f8, prim=0x7ffffffd57d0, nr_prims=1, ib=0x7ffffffd57b0, index_bounds_valid=0 '\000', min_index=4294967295, 
    max_index=4294967295) at vbo/vbo_exec_array.c:591
#8  0x00007fffd9bb1027 in vbo_validated_drawrangeelements (ctx=0x2e312f8, mode=1, index_bounds_valid=0 '\000', start=4294967295, end=4294967295, count=24, type=5125, 
    indices=0x0, basevertex=0, numInstances=1, baseInstance=0) at vbo/vbo_exec_array.c:1014
#9  0x00007fffd9bb130c in vbo_exec_DrawElements (mode=1, count=24, type=5125, indices=0x0) at vbo/vbo_exec_array.c:1164
#10 0x00007ffff7fc438d in glDrawElements (mode=1, count=24, type=5125, indices=0x0) at ../../../src/mapi/glapi/glapi_mapi_tmp.h:3705
#11 0x0000000000ca0c59 in ?? ()
#12 0x00000000008e3440 in ?? ()
#13 0x00000000008ebd85 in ?? ()
#14 0x00000000008ef424 in draw_object ()
#15 0x00000000008dfd88 in view3d_opengl_select ()
#16 0x00000000008d594e in ?? ()
#17 0x00000000008d8f53 in ?? ()
#18 0x00000000008d9790 in ?? ()
#19 0x0000000000827cba in ?? ()
#20 0x0000000000828c6e in ?? ()
#21 0x0000000000828f52 in ?? ()
#22 0x00000000008296f8 in ?? ()
#23 0x0000000000829b8b in wm_event_do_handlers ()
#24 0x0000000000822e28 in WM_main ()
#25 0x0000000000816bd5 in main ()
Comment 4 Iago Toral 2014-03-18 10:53:04 UTC
After some debugging I have more information.

glDrawElements will first attempt to map VBOs in bind_inputs() from tnl/t_draw.c.

Here, we have a named buffer object for which we first attempt to map the buffer calling ctx->Driver.MapBufferRange(). The mapping is for 432 bytes. This seems to return a valid address:

(gdb) p inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer
$38 = (GLvoid *) 0x7fffd8046000

(gdb) p *(char*)(inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer)
$17 = 0 '\000'

(gdb) p inputs[i]->BufferObj->Size
$4 = 432

But then the final address to be used is computed by adding an offset to the
mapped address like this:

ptr = ADD_POINTERS(inputs[i]->BufferObj->Mappings[MAP_INTERNAL].Pointer, inputs[i]->Ptr);

The offset stored in inputs[i]->Ptr, however, is too large for the size of the mapped buffer:

(gdb) p inputs[i]->Ptr
(const GLubyte *) 0xfffffff4 <Address 0xfffffff4 out of bounds>

which makes ptr point to an invalid address:

(gdb) p ptr
$37 = (const void *) 0x8000d8045ff4

(gdb) p ptr[0]
Cannot access memory at address 0x8000d8045ff4

Later on in the execution of glDrawElements(), when data is accessed we get the segfault, which happens as per the stacktrace I pasted before at:

COPY_CLEAN_4V(machine->VertAttribs[attr], size, data)

Where data seems to point to an offset from the invalid pointer address:

(gdb) p data
$3 = (const GLfloat *) 0x8000d998dff4

Removing the pointer addition with ADD_POINTERS does fix the crash although this is not the proper fix I guess. I suppose that inputs[i]->Ptr is not being properly initialized or gets corrupted at some point.
Comment 5 Iago Toral 2014-03-18 15:50:42 UTC
This large offset comes from vbo_exec_DrawElements() that passes
~0 for the start parameter, which then in vbo_rebase_prims(),
renamed as min_index, is used like this to set the value of Ptr in
the arrays:

for (i = 0; i < VERT_ATTRIB_MAX; i++) {
  tmp_arrays[i] = *arrays[i];
  tmp_arrays[i].Ptr += min_index * tmp_arrays[i].StrideB;
  tmp_array_pointers[i] = &tmp_arrays[i];

GDB shows where the problem shows up:

(gdb) p arrays[i].Ptr
$67 = (const GLubyte *) 0x0

(gdb) p min_index
$68 = 4294967295

(gdb) p tmp_arrays[i].StrideB
$69 = 12

(gdb) p (void*)(min_index * tmp_arrays[i].StrideB)
$72 = (void *) 0xfffffff4

This is the pointer offset that we will use later in bind_inputs() and which
will lead to an invalid memory address as I explain in the previous comment.

I don't understand well enough the semantics behind min_index here, but even
when it looks that passing ~0 in vbo_exec_DrawElements() has to be done for a
reason I wonder if this operation here is intended to happen with that value
too. Could it be that the implementation of this loop is not considering the
case where min_index has been set to ~0?
Comment 6 Iago Toral 2014-03-21 12:03:55 UTC
It looks like the problem starts in brw_draw_prims() from brw_draw.c. The problematic code is this:

   /* If we're going to have to upload any of the user's vertex arrays, then
    * get the minimum and maximum of their index buffer so we know what range
    * to upload.
   if (!vbo_all_varyings_in_vbos(arrays) && !index_bounds_valid) {
      perf_debug("Scanning index buffer to compute index buffer bounds.  "
                 "Use glDrawRangeElements() to avoid this.\n");
      vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims);

vbo_exec_DrawElements() will call this code with min_index and max_index set to ~0, and after the code above this will call  _tnl_draw_prims() with max_index and min_index. As far as I can see, _tnl_draw_prims() expects a sane value for max_index and min_index which is expected to be computed by bo_get_minmax_indices(), howver this is not happening here because vbo_all_varyings_in_vbos() evaluates to TRUE.

Is there a case where index_bounds_valid can be FALSE and still we don't want to compute index bounds? At least in this case that is the cause for the crash. Removing the vbo_all_varyings_in_vbos() from the condition computes proper index bounds and fixes the problem.
Comment 7 Iago Toral 2014-03-21 12:24:41 UTC
Created attachment 96158 [details] [review]

Fixes the crash in Blender when rendering to selection buffer by forcing a call to vbo_get_minmax_indices() when we don't have valid index bounds.

Maybe this is not a proper fix though since I don't know why vbo_all_varyings_in_vbos() was being tested to decide if we need to call vbo_get_minmax_indices even in the case where we know we don't have valid index bounds.

Eric wrote that code according to 'git blame' (the commit that adds that check is 2708ddfb06a36) so maybe he can tell whether this patch is valid or the solution has to be different.
Comment 8 Kenneth Graunke 2014-03-28 16:05:32 UTC

When vertex data is in a user array (normal memory), we need to copy it into a VBO in order for the GPU to be able to use it.  The Index Buffer allows random access, so we need to scan it to see which indices/elements of the vertex data are actually used.  Once we have the min and max element that's used for the drawing, we upload that.

If vertex data is already in VBOs, we don't need to upload it, so we normally don't need to know the min/max elements used.  The whole buffer will be available, and the GPU can use whatever it wants.

But, as you discovered, the TNL module (used for GL_FEEDBACK/GL_SELECT software fallbacks) apparently needs those bounds as well.

Should be fixed in master with:

commit 029ccd773d01a5f801c809c499516d7b0c4cc3f8
Author: Iago Toral Quiroga <itoral@igalia.com>
Date:   Fri Mar 28 08:14:02 2014 +0100

    i965: Make sure we always compute valid index bounds before drawing.
    When doing software rendering (i.e. rendering to the selection buffer) we need
    to make sure that we have valid index bounds before calling _tnl_draw_prims(),
    otherwise we can crash.
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59455
    Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>

Thanks for the patch!
Comment 9 Iago Toral 2014-03-31 07:05:31 UTC
Kenneth, thanks for taking the time to explain the details, I appreciate that!

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.