xref: /OK3568_Linux_fs/external/xserver/glamor/glamor_vbo.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright © 2014 Intel Corporation
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the next
12*4882a593Smuzhiyun  * paragraph) shall be included in all copies or substantial portions of the
13*4882a593Smuzhiyun  * Software.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*4882a593Smuzhiyun  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*4882a593Smuzhiyun  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*4882a593Smuzhiyun  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*4882a593Smuzhiyun  * IN THE SOFTWARE.
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /**
25*4882a593Smuzhiyun  * @file glamor_vbo.c
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * Helpers for managing streamed vertex bufffers used in glamor.
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include "glamor_priv.h"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /** Default size of the VBO, in bytes.
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * If a single request is larger than this size, we'll resize the VBO
35*4882a593Smuzhiyun  * and return an appropriate mapping, but we'll resize back down after
36*4882a593Smuzhiyun  * that to avoid hogging that memory forever.  We don't anticipate
37*4882a593Smuzhiyun  * normal usage actually requiring larger VBO sizes.
38*4882a593Smuzhiyun  */
39*4882a593Smuzhiyun #define GLAMOR_VBO_SIZE (512 * 1024)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun /**
42*4882a593Smuzhiyun  * Returns a pointer to @size bytes of VBO storage, which should be
43*4882a593Smuzhiyun  * accessed by the GL using vbo_offset within the VBO.
44*4882a593Smuzhiyun  */
45*4882a593Smuzhiyun void *
glamor_get_vbo_space(ScreenPtr screen,unsigned size,char ** vbo_offset)46*4882a593Smuzhiyun glamor_get_vbo_space(ScreenPtr screen, unsigned size, char **vbo_offset)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
49*4882a593Smuzhiyun     void *data;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun     glamor_make_current(glamor_priv);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun     glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun     if (glamor_priv->has_buffer_storage) {
56*4882a593Smuzhiyun         if (glamor_priv->vbo_size < glamor_priv->vbo_offset + size) {
57*4882a593Smuzhiyun             if (glamor_priv->vbo_size)
58*4882a593Smuzhiyun                 glUnmapBuffer(GL_ARRAY_BUFFER);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun             if (size > glamor_priv->vbo_size) {
61*4882a593Smuzhiyun                 glamor_priv->vbo_size = MAX(GLAMOR_VBO_SIZE, size);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun                 /* We aren't allowed to resize glBufferStorage()
64*4882a593Smuzhiyun                  * buffers, so we need to gen a new one.
65*4882a593Smuzhiyun                  */
66*4882a593Smuzhiyun                 glDeleteBuffers(1, &glamor_priv->vbo);
67*4882a593Smuzhiyun                 glGenBuffers(1, &glamor_priv->vbo);
68*4882a593Smuzhiyun                 glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun                 assert(glGetError() == GL_NO_ERROR);
71*4882a593Smuzhiyun                 glBufferStorage(GL_ARRAY_BUFFER, glamor_priv->vbo_size, NULL,
72*4882a593Smuzhiyun                                 GL_MAP_WRITE_BIT |
73*4882a593Smuzhiyun                                 GL_MAP_PERSISTENT_BIT |
74*4882a593Smuzhiyun                                 GL_MAP_COHERENT_BIT);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun                 if (glGetError() != GL_NO_ERROR) {
77*4882a593Smuzhiyun                     /* If the driver failed our coherent mapping, fall
78*4882a593Smuzhiyun                      * back to the ARB_mbr path.
79*4882a593Smuzhiyun                      */
80*4882a593Smuzhiyun                     glamor_priv->has_buffer_storage = false;
81*4882a593Smuzhiyun                     glamor_priv->vbo_size = 0;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun                     return glamor_get_vbo_space(screen, size, vbo_offset);
84*4882a593Smuzhiyun                 }
85*4882a593Smuzhiyun             }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun             glamor_priv->vbo_offset = 0;
88*4882a593Smuzhiyun             glamor_priv->vb = glMapBufferRange(GL_ARRAY_BUFFER,
89*4882a593Smuzhiyun                                                0, glamor_priv->vbo_size,
90*4882a593Smuzhiyun                                                GL_MAP_WRITE_BIT |
91*4882a593Smuzhiyun                                                GL_MAP_INVALIDATE_BUFFER_BIT |
92*4882a593Smuzhiyun                                                GL_MAP_PERSISTENT_BIT |
93*4882a593Smuzhiyun                                                GL_MAP_COHERENT_BIT);
94*4882a593Smuzhiyun         }
95*4882a593Smuzhiyun         *vbo_offset = (void *)(uintptr_t)glamor_priv->vbo_offset;
96*4882a593Smuzhiyun         data = glamor_priv->vb + glamor_priv->vbo_offset;
97*4882a593Smuzhiyun         glamor_priv->vbo_offset += size;
98*4882a593Smuzhiyun     } else if (glamor_priv->has_map_buffer_range) {
99*4882a593Smuzhiyun         /* Avoid GL errors on GL 4.5 / ES 3.0 with mapping size == 0,
100*4882a593Smuzhiyun          * which callers may sometimes pass us (for example, if
101*4882a593Smuzhiyun          * clipping leads to zero rectangles left).  Prior to that
102*4882a593Smuzhiyun          * version, Mesa would sometimes throw errors on unmapping a
103*4882a593Smuzhiyun          * zero-size mapping.
104*4882a593Smuzhiyun          */
105*4882a593Smuzhiyun         if (size == 0)
106*4882a593Smuzhiyun             return NULL;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun         if (glamor_priv->vbo_size < glamor_priv->vbo_offset + size) {
109*4882a593Smuzhiyun             glamor_priv->vbo_size = MAX(GLAMOR_VBO_SIZE, size);
110*4882a593Smuzhiyun             glamor_priv->vbo_offset = 0;
111*4882a593Smuzhiyun             glBufferData(GL_ARRAY_BUFFER,
112*4882a593Smuzhiyun                          glamor_priv->vbo_size, NULL, GL_STREAM_DRAW);
113*4882a593Smuzhiyun         }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun         data = glMapBufferRange(GL_ARRAY_BUFFER,
116*4882a593Smuzhiyun                                 glamor_priv->vbo_offset,
117*4882a593Smuzhiyun                                 size,
118*4882a593Smuzhiyun                                 GL_MAP_WRITE_BIT |
119*4882a593Smuzhiyun                                 GL_MAP_UNSYNCHRONIZED_BIT |
120*4882a593Smuzhiyun                                 GL_MAP_INVALIDATE_RANGE_BIT);
121*4882a593Smuzhiyun         *vbo_offset = (char *)(uintptr_t)glamor_priv->vbo_offset;
122*4882a593Smuzhiyun         glamor_priv->vbo_offset += size;
123*4882a593Smuzhiyun         glamor_priv->vbo_mapped = TRUE;
124*4882a593Smuzhiyun     } else {
125*4882a593Smuzhiyun         /* Return a pointer to the statically allocated non-VBO
126*4882a593Smuzhiyun          * memory. We'll upload it through glBufferData() later.
127*4882a593Smuzhiyun          */
128*4882a593Smuzhiyun         if (glamor_priv->vbo_size < size) {
129*4882a593Smuzhiyun             glamor_priv->vbo_size = MAX(GLAMOR_VBO_SIZE, size);
130*4882a593Smuzhiyun             free(glamor_priv->vb);
131*4882a593Smuzhiyun             glamor_priv->vb = xnfalloc(glamor_priv->vbo_size);
132*4882a593Smuzhiyun         }
133*4882a593Smuzhiyun         *vbo_offset = NULL;
134*4882a593Smuzhiyun         /* We point to the start of glamor_priv->vb every time, and
135*4882a593Smuzhiyun          * the vbo_offset determines the size of the glBufferData().
136*4882a593Smuzhiyun          */
137*4882a593Smuzhiyun         glamor_priv->vbo_offset = size;
138*4882a593Smuzhiyun         data = glamor_priv->vb;
139*4882a593Smuzhiyun     }
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun     return data;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun void
glamor_put_vbo_space(ScreenPtr screen)145*4882a593Smuzhiyun glamor_put_vbo_space(ScreenPtr screen)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun     glamor_make_current(glamor_priv);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun     if (glamor_priv->has_buffer_storage) {
152*4882a593Smuzhiyun         /* If we're in the ARB_buffer_storage path, we have a
153*4882a593Smuzhiyun          * persistent mapping, so we can leave it around until we
154*4882a593Smuzhiyun          * reach the end of the buffer.
155*4882a593Smuzhiyun          */
156*4882a593Smuzhiyun     } else if (glamor_priv->has_map_buffer_range) {
157*4882a593Smuzhiyun         if (glamor_priv->vbo_mapped) {
158*4882a593Smuzhiyun             glUnmapBuffer(GL_ARRAY_BUFFER);
159*4882a593Smuzhiyun             glamor_priv->vbo_mapped = FALSE;
160*4882a593Smuzhiyun         }
161*4882a593Smuzhiyun     } else {
162*4882a593Smuzhiyun         glBufferData(GL_ARRAY_BUFFER, glamor_priv->vbo_offset,
163*4882a593Smuzhiyun                      glamor_priv->vb, GL_DYNAMIC_DRAW);
164*4882a593Smuzhiyun     }
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun     glBindBuffer(GL_ARRAY_BUFFER, 0);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun void
glamor_init_vbo(ScreenPtr screen)170*4882a593Smuzhiyun glamor_init_vbo(ScreenPtr screen)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun     glamor_make_current(glamor_priv);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun     glGenBuffers(1, &glamor_priv->vbo);
177*4882a593Smuzhiyun     glGenVertexArrays(1, &glamor_priv->vao);
178*4882a593Smuzhiyun     glBindVertexArray(glamor_priv->vao);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun void
glamor_fini_vbo(ScreenPtr screen)182*4882a593Smuzhiyun glamor_fini_vbo(ScreenPtr screen)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun     glamor_make_current(glamor_priv);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun     glDeleteVertexArrays(1, &glamor_priv->vao);
189*4882a593Smuzhiyun     glamor_priv->vao = 0;
190*4882a593Smuzhiyun     if (!glamor_priv->has_map_buffer_range)
191*4882a593Smuzhiyun         free(glamor_priv->vb);
192*4882a593Smuzhiyun }
193