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