class_docstr: Generic GPU buffer.
  
  A generic buffer is an interface used to upload data to a GPU array buffer
  (ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER). It keeps track of
  buffer size but does not have any CPU storage. You can consider it as
  write-only.
  
  The `set_data` is a deferred operation: you can call it even if an OpenGL
  context is not available. The `update` function is responsible to upload
  pending data to GPU memory and requires an active GL context.
  
  The Buffer class only deals with data in terms of bytes; it is not
  aware of data type or element size.
  
  Parameters
  ----------
  data : ndarray | None
      Buffer data.
  nbytes : int | None
      Buffer byte size.
class_docstr_tok: ["Generic","GPU","buffer",".","A","generic","buffer","is","an","interface","used","to","upload","data","to","a","GPU","array","buffer","(","ARRAY_BUFFER","or","ELEMENT_ARRAY_BUFFER",")",".","It","keeps","track","of","buffer","size","but","does","not","have","any","CPU","storage",".","You","can","consider","it","as","write-only",".","The","`","set_data","`","is","a","deferred","operation",":","you","can","call","it","even","if","an","OpenGL","context","is","not","available",".","The","`","update","`","function","is","responsible","to","upload","pending","data","to","GPU","memory","and","requires","an","active","GL","context",".","The","Buffer","class","only","deals","with","data","in","terms","of","bytes",";","it","is","not","aware","of","data","type","or","element","size",".","Parameters","--","--","--","--","--","data",":","ndarray","|","None","Buffer","data",".","nbytes",":","int","|","None","Buffer","byte","size","."]
docstr: Set data in the buffer (deferred operation).
  
  This completely resets the size and contents of the buffer.
  
  Parameters
  ----------
  data : ndarray
      Data to be uploaded
  copy: bool
      Since the operation is deferred, data may change before
      data is actually uploaded to GPU memory.
      Asking explicitly for a copy will prevent this behavior.
code: def set_data(self, data, copy=False):
      """Set data in the buffer (deferred operation).
  
      This completely resets the size and contents of the buffer.
  
      Parameters
      ----------
      data : ndarray
          Data to be uploaded
      copy: bool
          Since the operation is deferred, data may change before
          data is actually uploaded to GPU memory.
          Asking explicitly for a copy will prevent this behavior.
      """
      data = np.array(data, copy=copy)
      nbytes = data.nbytes
  
      if nbytes != self._nbytes:
          self.resize_bytes(nbytes)
      else:
          # Use SIZE to discard any previous data setting
          self._glir.command("SIZE", self._id, nbytes)
  
      if nbytes:  # Only set data if there *is* data
          self._glir.command("DATA", self._id, 0, data)
  
imports: import numpy
  from os import path
  from traceback import extract_stack, format_list
  import weakref
  from .globject import GLObject
  from ..util import logger
label_desc: Use image node_id 4 for calling the Buffer obj's underlying member method code with example usage: obj.set_data(data, copy) without return types