Data copy from one VBO to another VBO inside VRAM

Hi all,

I’ve searched over the net to get some help on this but couldn’t find none. I would like to do something as I posted in this thread http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=276432#Post276432

Summarizing, I have a kind of 3D object that presents different levels of detail, something like what tessellation does. So I would like to send to the VRAM only the geometry of the vertices that I strictly necessary to draw the mesh at a given level of detail. And I would like to have the flexibility to increase the detail and send only the new vertices or when decreasing the details I would like to be able to erase the vertices that will no longer be rendered. As Dark Phanton and Alfonse suggested, I cannot merge buffers using classical openGL API (maybe GLSL could do the trick, but I’m not even newbie in GLSL!).

My question here would be this one. Imagine I load two buffers in the VRAM, each with vertices of 2 different levels of detail. Now I create a 3rd buffer that should contain the information of both buffers, so that I can use this 3rd one to apply the draw command. Is it possible in to create this 3rd buffer by copying information from the 2 other VBOs inside the VRAM? Somthing like buffersubdata but from VRAM to VRAM instead of RAM to VRAM (kind of memcpy in C/C++ for system RAM). Sure, I would double the data inside the VRAM but at least I could erase only the buffers of high detail whenever I want to decrease the mesh detail, or send only the new vertices when increasing the detail. Plus, mem copy inside VRAM should be (much) faster than RAM->VRAM transfers. How does tessellation menage the memory when creating new geometry detail? Any thoughts?

I know that one can copy data from VBO to texture memory, but texture memory are limited in size, so it would not help if I have some millions of vertices to draw.

Thx for your time,

Leo

I’d use TransformFeedback for this.
Alternatively, you can bind both VBO’s as TBO’s and render copying from one 1D texture buffer to another.

Um, ARB_copy_buffer. It’s been core GL since 3.1.

Nice! didn’t know about this extension :slight_smile:

@dmitry: I’ll check it out. I’ll compare with the copy_buffer extension that Alfonse suggests. Thanks :wink:

@Alfonse: Hi Alfonse, thx again :slight_smile: Well, for now I’m using openGL inside C# code (for easier windowing management - buttons, straps and others), so I’m using TAO framework to include the unsafe openGL functions on C# (and as a bonus it creates the openGL context in the window form). The problem here is that TAO framework seems to support only openGL 2.1 . So: is there another way to include more recent openGL versions in C# or shall I say goodbye to C# and come back to C/C++? (and manage all contexts and buttons and straps and stuff otherwise :/)

thx again :wink:

leo

I strongly advice OpenTK for GL development under net/mono.
Using it myself for GL3 context. Great support and convenient interface.
http://www.opentk.com

Another solution that I’ve just thought about would consist on I myself include this copy_buffer function into a class of mine by calling the dll, something like this:


using System;
using System.Runtime.InteropServices;

namespace myNameSpace
{
    class myGLclass
    {
        public const int GL_COPY_READ_BUFFER = 0x8F36;
        public const int GL_COPY_WRITE_BUFFER = 0x8F37;

        [DllImport("opengl32")]
        public static extern void glCopyBufferSubData(int readtarget, int writetarget, IntPtr readoffset, IntPtr writeoffset, IntPtr size);
    }
}

then type myGlcalss.glCopyBufferSubData(…); which is more or less what openTK or TAO do. However, the opengl32 included in windows seems to be the 1.0 version because it doesn’t even support the VBO functions! So, where can I find the opengl.dll of the 4.0 version? I read around here that we don’t have a unique SDK file, but at the same time I could not find the link to download at least the dll of the core functions.

Thx, Leo

Opengl32.dll is provided by your video driver.

well, “I” managed to include the glCopyBufferSubData in my application. I did so by coping from TAO Framework the way they do to include functions from opengl32.dll But it is really, really cumbersome to add only one poor function: (from tao framework)


using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace myNamespace
{
    public static class myGlClass
    {
        internal static class Imports
        {
            internal static SortedList<string, MethodInfo> FunctionMap;  // This is faster than either Dictionary or SortedDictionary
            static Imports()
            {
                MethodInfo[] methods = importsClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
                FunctionMap = new SortedList<string, MethodInfo>(methods.Length);
                foreach (MethodInfo m in methods)
                    FunctionMap.Add(m.Name, m);
            }

            [System.Runtime.InteropServices.DllImport("opengl32.dll", EntryPoint = "glCopyBufferSubData", ExactSpelling = true)]
            internal extern static void CopyBufferSubData(int readtarget, int writetarget, IntPtr readoffset, IntPtr writeoffset, IntPtr size);
        }

        internal static class Delegates
        {
            [System.Security.SuppressUnmanagedCodeSecurity()]
            internal delegate void CopyBufferSubData(int readtarget, int writetarget, IntPtr readoffset, IntPtr writeoffset, IntPtr size);
            internal static CopyBufferSubData glCopyBufferSubData;
        }

        private static Type glClass;
        private static Type delegatesClass;
        private static Type importsClass;
        private static FieldInfo[] delegates;
        private static bool rebuildExtensionList;
        private static IGetProcAddress getProcAddress;

        internal interface IGetProcAddress
        {
            IntPtr GetProcAddress(string function);
        }

        static myGlClass()
        {
            glClass = typeof(myGlClass);
            delegatesClass = glClass.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);
            importsClass = glClass.GetNestedType("Imports", BindingFlags.Static | BindingFlags.NonPublic);
            // 'Touch' Imports class to force initialization. We don't want anything yet, just to have
            // this class ready.
            if (Imports.FunctionMap != null) { }
            ReloadFunctions();
        }

        public static void ReloadFunctions()
        {
            // Using reflection is more than 3 times faster than directly loading delegates on the first
            // run, probably due to code generation overhead. Subsequent runs are faster with direct loading
            // than with reflection, but the first time is more significant.

            if (delegates == null)
                delegates = delegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic);

            foreach (FieldInfo f in delegates)
                f.SetValue(null, GetDelegate(f.Name, f.FieldType));

            rebuildExtensionList = true;
        }

        public static Delegate GetDelegate(string name, Type signature)
        {
            MethodInfo m;
            return GetExtensionDelegate(name, signature) ??
                  (Imports.FunctionMap.TryGetValue((name.Substring(2)), out m) ?
                   Delegate.CreateDelegate(signature, m) : null);
        }

        internal static Delegate GetExtensionDelegate(string name, Type signature)
        {
            IntPtr address = GetAddress(name);

            if (address == IntPtr.Zero ||
                address == new IntPtr(1) ||     // Workaround for buggy nvidia drivers which return
                address == new IntPtr(2))       // 1 or 2 instead of IntPtr.Zero for some extensions.
            {
                return null;
            }
            else
            {
                return Marshal.GetDelegateForFunctionPointer(address, signature);
            }
        }

        private static IntPtr GetAddress(string function)
        {
            if (getProcAddress == null)
            {
                if (System.Environment.OSVersion.Platform == PlatformID.Win32NT ||
                    System.Environment.OSVersion.Platform == PlatformID.Win32S ||
                    System.Environment.OSVersion.Platform == PlatformID.Win32Windows ||
                    System.Environment.OSVersion.Platform == PlatformID.WinCE)
                {
                    getProcAddress = new GetProcAddressWindows();
                }
                else if (System.Environment.OSVersion.Platform == PlatformID.Unix ||
                         System.Environment.OSVersion.Platform == (PlatformID)4)
                {
                    // Distinguish between Unix and Mac OS X kernels.
                    switch (DetectUnixKernel())
                    {
                        case "Unix":
                        case "Linux":
                            getProcAddress = new GetProcAddressX11();
                            break;

                        case "Darwin":
                            getProcAddress = new GetProcAddressOSX();
                            break;

                        default:
                            throw new PlatformNotSupportedException(
                                DetectUnixKernel() + ": Unknown Unix platform - cannot load extensions. Please report a bug at http://taoframework.com");
                    }
                }
                else
                {
                    throw new PlatformNotSupportedException(
                        "Extension loading is only supported under Mac OS X, Unix/X11 and Windows. We are sorry for the inconvience.");
                }
            }

            return getProcAddress.GetProcAddress(function);
        }

        private static string DetectUnixKernel()
        {
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.Arguments = "-s";
            startInfo.RedirectStandardOutput = true;
            startInfo.RedirectStandardError = true;
            startInfo.UseShellExecute = false;
            foreach (string unameprog in new string[] { "/usr/bin/uname", "/bin/uname", "uname" })
            {
                try
                {
                    startInfo.FileName = unameprog;
                    Process uname = Process.Start(startInfo);
                    StreamReader stdout = uname.StandardOutput;
                    return stdout.ReadLine().Trim();
                }
                catch (System.IO.FileNotFoundException)
                {
                    // The requested executable doesn't exist, try next one.
                    continue;
                }
                catch (System.ComponentModel.Win32Exception)
                {
                    continue;
                }
            }
            return null;
        }

        internal class GetProcAddressWindows : IGetProcAddress
        {
            [System.Runtime.InteropServices.DllImport("opengl32.dll", EntryPoint = "wglGetProcAddress", ExactSpelling = true)]
            private static extern IntPtr wglGetProcAddress(String lpszProc);

            public IntPtr GetProcAddress(string function)
            {
                return wglGetProcAddress(function);
            }
        }

        internal class GetProcAddressX11 : IGetProcAddress
        {
            [DllImport("opengl32.dll", EntryPoint = "glXGetProcAddress")]
            private static extern IntPtr glxGetProcAddress([MarshalAs(UnmanagedType.LPTStr)] string procName);

            public IntPtr GetProcAddress(string function)
            {
                return glxGetProcAddress(function);
            }
        }

        internal class GetProcAddressOSX : IGetProcAddress
        {
            private const string Library = "libdl.dylib";

            [DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
            private static extern bool NSIsSymbolNameDefined(string s);
            [DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
            private static extern IntPtr NSLookupAndBindSymbol(string s);
            [DllImport(Library, EntryPoint = "NSAddressOfSymbol")]
            private static extern IntPtr NSAddressOfSymbol(IntPtr symbol);

            public IntPtr GetProcAddress(string function)
            {
                string fname = "_" + function;
                if (!NSIsSymbolNameDefined(fname))
                    return IntPtr.Zero;

                IntPtr symbol = NSLookupAndBindSymbol(fname);
                if (symbol != IntPtr.Zero)
                    symbol = NSAddressOfSymbol(symbol);

                return symbol;
            }
        }
        
        [System.CLSCompliant(false)]
        public static 
        void glCopyBufferSubData(int readtarget, int writetarget, IntPtr readoffset, IntPtr writeoffset, IntPtr size)
        {
            Delegates.glCopyBufferSubData((int) readtarget, (int) writetarget, (IntPtr) readoffset, (IntPtr) writeoffset, (IntPtr) size);
        }

        public const int GL_COPY_READ_BUFFER = 0x8F36;
        public const int GL_COPY_WRITE_BUFFER = 0x8F37;
    }
}

It is quite “weird” because functions included up to the OpenGL 1.1 version can be included really sooooooo easy just by doing this:


using System;
using System.Runtime.InteropServices;

namespace myNameSpace
{
    class myGLclass
    {
        [DllImport("opengl32")]
        public static extern void glVertex3f(float x, float y, float z);
    }
}

maybe this is so because they are present in the Gl.h, duno…

Anyway, I’ll try to analyze it and simplify it (I hope that it will be possible).

To conclude, this C:\Windows\System32\opengl32.dll already have at least the OpenGL 3.1 version functions. I don’t know if it is Microsoft that includes it with win7 or if it is ATI who overwrites it when I install the graphic drivers (is this what you mean DmitryM?).

Just to add, I included this line:


WINGDIAPI void APIENTRY glCopyBufferSubData(int readtarget, int writetarget, int *readoffset, int *writeoffset, int *size);

in the GL.h file (in C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\gl folder) and included this in myGLClass


[DllImport("opengl32.dll", EntryPoint = "glCopyBufferSubData", ExactSpelling = true)]
        public static extern void glCopyBufferSubData(int readtarget, int writetarget, int[] @readoffset, int[] @writeoffset, int[] @size);

but it didn’t worked out. So, I’ll keep trying to find out a simpler way to include (bind) this function in my application. The ideal solution would be to not rely on OpenTK, since the support to OpenGL can stop (like TAO), not to mention that it would avoid to ship more and more dlls with my appli. I already started to write the instructions to create/destroy the opengl contexts to my appli, equally to not rely on TAO nor OpenTK, so that I’ll depend only on the dlls shipped with windows (user32.dll, kernel.dll, opengl.dll and so on). I’m open to suggestions :slight_smile: But if you feel this is not the place to discuss about this, no problem, I can understand.

thx again for your time and suggestions,

leo

Hi all,

well, I created a little code using the glCopyBufferSubData function. However, there’s something still missing to glCopyBufferSubData be a nice solution or I miss something (which would not be a surprise!). Imagine this simple code:


int vbo1, ibo;
glGenBuffers(1, &vbo1);
glGenBuffers(1, &ibo);

//mesh
float geo_TRI[] = {-1,0,0,   0,1,0,    1,0,0};
uint topo_TRI[] = {   0,       1,        2};

//vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * 3, geo_TRI, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);

//index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint) * 3, topo_TRI, GL_STATIC_DRAW);

//draw
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, (char *) NULL);
glDisableClientState(GL_VERTEX_ARRAY);

very well, now I want to copy part of vbo1 to another buffer and draw from it. There is where I have the problem. If I bind the second buffer as an GL_COPY_READ_BUFFER or GL_COPY_WRITE_BUFFER and copy like:


glBindBuffer(GL_ARRAY_BUFFER, vbo1);

//create vbo2 of type GL_COPY_WRITE_BUFFER
glGenBuffers(1, &vbo2);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glBufferData(GL_COPY_WRITE_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//copy data from vbo1 to it
glCopyBufferSubData(GL_ARRAY_BUFFER,GL_COPY_WRITE_BUFFER,0,0,sizeof(float) * 2 * 3);
glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);

//delete buffer vbo1
Gl.glDeleteBuffers(1, vbo1);
vbo1 = 0;

//draw from vbo2
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, (char *) NULL);
glDisableClientState(GL_VERTEX_ARRAY);

then it “draws” a big red X. I believe that it is so because the draw functions seeks for an array with type GL_ARRAY_BUFFER to draw, which has been deleted. It finds only a buffer with type GL_COPY_WRITE_BUFFER (or GL_COPY_READ_BUFFER). A first question: these new buffer types (GL_COPY_WRITE_BUFFER or GL_COPY_READ_BUFFER) can’t be used to draw??? The second buffer can’t be GL_ARRAY_BUFFER neither, because the copy function will do a copy of the last binded buffer of type GL_ARRAY_BUFFER over itself! Therefore, if GL_COPY_READ_BUFFER or GL_COPY_WRITE_BUFFER cannot be used to draw, it would means that I have to use a GL_ARRAY_BUFFER through two copies like:


int vbotemp;

glBindBuffer(GL_ARRAY_BUFFER, vbo1);

//create a temp buffer of type GL_COPY_READ_BUFFER
glGenBuffers(1, &vbotemp);
glBindBuffer(GL_COPY_READ_BUFFER, vbotemp);
glBufferData(GL_COPY_READ_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//copy data from vbo1 to it
glCopyBufferSubData(GL_ARRAY_BUFFER,GL_COPY_READ_BUFFER,0,0,sizeof(float) * 2 * 3);

//Delete buffer vbo1
Gl.glDeleteBuffers(1, vbo1);
vbo1 = 0;

//generate buffer vbo2 of type GL_ARRAY_BUFFER
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//copy data from vbotemp to it
glCopyBufferSubData(GL_COPY_READ_BUFFER,GL_ARRAY_BUFFER,0,0,sizeof(float) * 2 * 3);
glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);

//Delete buffer vbotemp
Gl.glDeleteBuffers(1, vbotemp);
vbotemp = 0;

//draw from vbo2
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, (char *) NULL);
glDisableClientState(GL_VERTEX_ARRAY);

or eventually do not create a vbo2 but “resize” vbo1:


int vbotemp;

glBindBuffer(GL_ARRAY_BUFFER, vbo1);

//create a temp buffer of type GL_COPY_READ_BUFFER
glGenBuffers(1, &vbotemp);
glBindBuffer(GL_COPY_READ_BUFFER, vbotemp);
glBufferData(GL_COPY_READ_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//copy data from vbo1 to it
glCopyBufferSubData(GL_ARRAY_BUFFER,GL_COPY_READ_BUFFER,0,0,sizeof(float) * 2 * 3);

//Resize buffer vbo1
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//copy data from vbotemp to vbo1
glCopyBufferSubData(GL_COPY_READ_BUFFER,GL_ARRAY_BUFFER,0,0,sizeof(float) * 2 * 3);

//Delete buffer vbotemp
Gl.glDeleteBuffers(1, vbotemp);
vbotemp = 0;

//draw from vbo1
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, (char *) NULL);
glDisableClientState(GL_VERTEX_ARRAY);

either ways, this would means an undesirable additional copy…

A second question: when I reuse glBufferData over the same buffer with a different size it delete and allocates a buffer with the new size? Or do not change the size but just delete?

But the main question still is: is there a way to draw from the second buffer without double copy?

Thx,

leo

a little up here. Do I really need two copies with glCopyBufferSubData to get data on a “drawable” buffer? Any thoughts on it?

leo

ok, I found a solution. It is really simple, but had to think about it. When you copy from the buffer of type GL_ARRAY_BUFFER to the temporary one of type GL_COPY_READ_BUFFER (or GL_COPY_WRITE_BUFFER) you can delete the GL_ARRAY_BUFFER buffer and rebind the GL_COPY_READ_BUFFER (or GL_COPY_WRITE_BUFFER) to GL_ARRAY_BUFFER type. Like:


int vbotemp;

glBindBuffer(GL_ARRAY_BUFFER, vbo1);

//create a temp buffer of type GL_COPY_READ_BUFFER
glGenBuffers(1, &vbotemp);
glBindBuffer(GL_COPY_READ_BUFFER, vbotemp);
glBufferData(GL_COPY_READ_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//copy data from vbo1 to it
glCopyBufferSubData(GL_ARRAY_BUFFER,GL_COPY_READ_BUFFER,0,0,sizeof(float) * 2 * 3);

//Instead of resize and copy a second and undesirable time...
/*
//Resize buffer vbo1
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//Copy data from vbotemp to vbo1
glCopyBufferSubData(GL_COPY_READ_BUFFER,GL_ARRAY_BUFFER,0,0,sizeof(float) * 2 * 3);
*/

//... we just rebind vbotemp as GL_ARRAY_BUFFER and...
glBindBuffer(GL_ARRAY_BUFFER, vbotemp);
glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);

//...don't erase the "temporary buffer" but just the old one
/*
//Delete buffer vbotemp
glDeleteBuffers(1, vbotemp);
vbotemp = 0;
*/
glDeleteBuffers(1, vbo1);
vbo1 = vbotemp;

//draw from vbo1
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, (char *) NULL);
glDisableClientState(GL_VERTEX_ARRAY);

It is a little weird/odd as concept but it seems to work. In my modest opinion if should work bindless, i.e., using the buffer name not the type.

But well, this is it. Thx for your time,

leo

When you copy from the buffer of type GL_ARRAY_BUFFER

OK, stop right there.

GL_ARRAY_BUFFER is a binding location, not a type. Buffer objects do not have types. They are simply unformatted memory.

You can bind a buffer object to GL_TRANSFORM_FEEDBACK_BUFFER to do some transform feedback, then bind that buffer to GL_ARRAY_BUFFER to do some attribute transfers and rendering, then to GL_UNIFORM_BUFFER to use it as a uniform buffer, and then to GL_PIXEL_UNPACK_BUFFER to upload data to a texture. All with the same buffer object. No glBufferData, no respecifying. Nothing.

Targets have specific semantics associated with them. GL_ARRAY_BUFFER is used for associating a buffer object with vertex attributes when doing glDraw* calls. GL_UNIFORM_BUFFER is used for associating a buffer object with uniform data. And so on.

The only reason GL_COPY_READ_BUFFER and GL_COPY_WRITE_BUFFER exist is to allow you to bind to read/write locations that don’t have any specific semantics associated with them. That way, if you have something important bound to GL_ARRAY_BUFFER or whatever, you don’t have to unbind it just to do a copy.

Targets only matter as far as their semantic utility is concerned*. All buffer objects are equal, endowed by their creator with certain inalienable rights. You may wish to read the wiki page on Buffer Objects, for more details.

*: Implementations are allowed to make inferences on how you intend to use a buffer object based on the particular target you choose when you first allocate memory for it with glBufferData. But that’s it. And even that only affects performance, if it affects anything at all.

when you talk about binding location, do you mean physical location in the VRAM? I mean, when I bind a buffer to GL_ARRAY_BUFFER then to GL_TRANSFORM_FEEDBACK_BUFFER does it make data copy/transfer to another memory location (to do whatever you want to do with it after binding)? Or data stays in the same place (I would hope so)?

Here’s one interesting thing I read in this wiki page you link: “In the technical sense, the target a buffer is bound to does not matter for the purposes of creating the memory storage for it. However, OpenGL implementations are allowed to make judgments about your intended use of the buffer object based on the first target you bind it to. So if you intend for your buffer object to be used as a vertex array buffer, you should bind that buffer to GL_ARRAY_BUFFER first. You may later use it as a GL_TRANSFORM_FEEDBACK buffer for readback or whatever, but binding it to GL_ARRAY_BUFFER gives the implementation important information about how you plan to use it overall.” So I guess it is telling me that if I’ll use the new buffer to hold vertex data for future drawing I should first bind it as a GL_ARRAY_BUFFER, then as a GL_COPY_WRITE_BUFFER to be filled with glCopyBufferSubData() then rebind it to GL_ARRAY_BUFFER for final draw. This is something I really haven’t any clue about.

Sry for so many questions, but it is a little fussy to me on how all this is implemented for real. Btw, where can we find the source code for opengl functions? It would be intersting to see what is coded behind functions like glbindbuffer or glcopybuffersubdata.

leo

when you talk about binding location, do you mean physical location in the VRAM?

No; that’s just a different term for target. GL_PIXEL_UNPACK_BUFFER and so forth.

So I guess it is telling me that if I’ll use the new buffer to hold vertex data for future drawing I should first bind it as a GL_ARRAY_BUFFER, then as a GL_COPY_WRITE_BUFFER to be filled with glCopyBufferSubData() then rebind it to GL_ARRAY_BUFFER for final draw.

What I said was that you should create the buffer in the location that you primarily intend to use it in. Creating the buffer involves generating a buffer object with glGenBuffers, followed by binding it to a location (GL_ARRAY_BUFFER, etc) and calling glBufferData on that location.

After that, you can do whatever you need with it.

Btw, where can we find the source code for opengl functions?

As a general rule, you can’t. You can download MESA GL, but there’s a pretty good chance that’s not the OpenGL implementation you’re running.

The “Open” part of OpenGL does not mean “Open Source.” It means that the specification is “Open” and freely accessible, thus allowing anyone to write an implementation of it.

OK, very well. Thank you for taking the time to clarify these doubts of mine. About the “open” term, I was thinking indeed that it was open source :slight_smile: But well, it already is a good thing it is free for use and available on several OS’s and implemented by the major gc manufacturers.

What I said was that you should create the buffer in the location that you primarily intend to use it in. Creating the buffer involves generating a buffer object with glGenBuffers, followed by binding it to a location (GL_ARRAY_BUFFER, etc) and calling glBufferData on that location.

In this case I’m doing this now:


int vbo1,vbo2;

float geo_TRI[] = {-1,0,0,   0,1,0,    1,0,0};

//create vbo1
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * 3, geo_TRI, GL_STATIC_DRAW);

//
// After doing whatever I shall do with vbo1, includin drawing,
// I can dispose of part its data for the matter of memory saving, 
// given that I need only part of information it contains.
//

//create vbo2 to hold part of vbo1 data
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 2 * 3, NULL, GL_STATIC_COPY);

//rebind buffers to copy from vbo1 to vbo2
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_ARRAY_BUFFER,GL_COPY_WRITE_BUFFER,0,0,sizeof(float) * 2 * 3);

//delete vbo1 to free memory and rebind vbo2 for drawing (glDraw[...]() calls)
glDeleteBuffers(1, vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);
vbo1 = vbo2;

//draw from the new buffer (supposing that the index buffer is set)
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, (char *) NULL);
glDisableClientState(GL_VERTEX_ARRAY);

well, I certainly double part of data on vbo1 when copying, but it is at most temporally. Anyway, it is better than noting since I can’t see any other solution to keep part of a buffer data without memory doubling (except using GLSL data positioning tricks), given that merging/splitting smaller buffers or resizing (without deleting its content) is not feasible in opengl (even if I still think that virtual merging - with no data moving - would not harm performance when merging a few big buffers).

thx again,

leo