示例#1
0
PIGLIT_GL_TEST_CONFIG_END


void
piglit_init(int argc, char **argv)
{
	bool pass = true;
	const int buffer_size = 1<<20;
	unsigned int buffer;
	char *mapped_data;
	static const char *const data_zero = "\x00\x00\x00\x00";
	static const char *const data_one  = "\xff\xff\xff\xff";
	static const char *const data_init = "\xff\xff\xff\xff"
					     "\xff\xff\xff\xff"
					     "\x00\x00\x00\x00"
					     "\x00\x00\x00\x00"
					     "\x55\x55\x55\x55"
					     "\x55\x55\x55\x55"
					     "\xaa\xaa\xaa\xaa"
					     "\xaa\xaa\xaa\xaa"
					     "\xff\x00\xff\x00"
					     "\xff\x00\xff\x00"
					     "\x00\xff\x00\xff"
					     "\x00\xff\x00\xff"
					     "\x91\xcc\x45\x36"
					     "\xd3\xe4\xe3\x5b"
					     "\x79\x1e\x21\x39"
					     "\xa8\xfa\x69\x6a";


	piglit_require_extension("GL_ARB_clear_buffer_object");

	glGenBuffers(1, &buffer);
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	glBufferData(GL_ARRAY_BUFFER, buffer_size, NULL, GL_STREAM_READ);
	fill_array_buffer(64, data_init);

	mapped_data = glMapBufferRange(GL_ARRAY_BUFFER, 0, buffer_size/2,
			GL_MAP_WRITE_BIT);
	memset(mapped_data, '\x00', buffer_size/2);
	glClearBufferSubData(GL_ARRAY_BUFFER, GL_RGBA8, buffer_size/2,
			buffer_size/2, GL_RGBA, GL_UNSIGNED_BYTE, data_one);
	glUnmapBuffer(GL_ARRAY_BUFFER);

	pass = check_array_buffer_sub_data(0, buffer_size/2,
			4, data_zero) && pass;
	pass = check_array_buffer_sub_data(buffer_size/2, buffer_size/2,
			4, data_one) && pass;

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glDeleteBuffers(1, &buffer);

	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;

	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
}
示例#2
0
void OGL_StructuredBuffer::BindToRenderTarget(unsigned int currentBindingPoint)
{
  // clear atomic counter
  if(flags & APPEND_SBF)
  {
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, structuredBufferName);
    GLuint clearData = 0;
    glClearBufferSubData(GL_SHADER_STORAGE_BUFFER, GL_R32UI, 0, sizeof(GLuint), GL_LUMINANCE, GL_UNSIGNED_INT, &clearData);
  }

  glBindBufferBase(GL_SHADER_STORAGE_BUFFER, currentBindingPoint, structuredBufferName);
}
示例#3
0
static void
clear_buffer(int i, unsigned offset, unsigned size, unsigned char value, char *cpu)
{
	glClearBufferSubData(GL_ARRAY_BUFFER, GL_R8, offset, size,
			     GL_RED, GL_UNSIGNED_BYTE, &value);
	memset(cpu+offset, value, size);

	if (debug && !check_array_buffer_data(SIZE, cpu)) {
		printf("Clear %i failed: offset=%i (%%4 = %i), size=%i (%%4 = %i)\n",
		       i, offset, offset % 4, size, size % 4);
		piglit_report_result(PIGLIT_FAIL);
	}
}
示例#4
0
文件: Buffer.cpp 项目: voxelinc/glow
void Buffer::clearSubData(GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data)
{
    if (m_directStateAccess)
    {
        glClearNamedBufferSubDataEXT(m_id, internalformat, offset, size, format, type, data);
        CheckGLError();
    }
    else
    {
        bind();

        glClearBufferSubData(m_target, internalformat, offset, size, format, type, data);
        CheckGLError();
    }
}
示例#5
0
void display()
{
	// Setup blending
	glEnable(GL_BLEND);
	glBlendEquation(GL_FUNC_ADD);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// Compute the MVP (Model View Projection matrix)
	{
		glBindBuffer(GL_UNIFORM_BUFFER, BufferName[buffer::TRANSFORM]);
		glm::mat4* Pointer = (glm::mat4*)glMapBufferRange(
			GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4),
			GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

		glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
		glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Window.TranlationCurrent.y));
		glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Window.RotationCurrent.y, glm::vec3(1.f, 0.f, 0.f));
		glm::mat4 View = glm::rotate(ViewRotateX, Window.RotationCurrent.x, glm::vec3(0.f, 1.f, 0.f));
		glm::mat4 Model = glm::mat4(1.0f);
		glm::mat4 MVP = Projection * View * Model;

		*Pointer = MVP;

		glUnmapBuffer(GL_UNIFORM_BUFFER);
	}

	glm::uint Data(0);
	glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, BufferName[buffer::ATOMIC_COUNTER]);
	glClearBufferSubData(GL_ATOMIC_COUNTER_BUFFER, GL_R8UI, 0, sizeof(glm::uint), GL_RGBA, GL_UNSIGNED_INT, &Data);

	glViewportIndexedf(0, 0, 0, float(Window.Size.x), float(Window.Size.y));
	glClearBufferfv(GL_COLOR, 0, &glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)[0]);

	glBindProgramPipeline(PipelineName);
	glBindVertexArray(VertexArrayName);
	glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, BufferName[buffer::ATOMIC_COUNTER]);
	glBindBufferBase(GL_UNIFORM_BUFFER, glf::semantic::uniform::TRANSFORM0, BufferName[buffer::TRANSFORM]);

	glDrawElementsInstancedBaseVertexBaseInstance(
		GL_TRIANGLES, ElementCount, GL_UNSIGNED_SHORT, 0, 5, 0, 0);

	glf::swapBuffers();
}
示例#6
0
文件: view.c 项目: Moteesh/reactos
void wined3d_unordered_access_view_clear_uint(struct wined3d_unordered_access_view *view,
        const struct wined3d_uvec4 *clear_value, struct wined3d_context *context)
{
    const struct wined3d_gl_info *gl_info = context->gl_info;
    const struct wined3d_format *format;
    struct wined3d_resource *resource;
    struct wined3d_buffer *buffer;
    unsigned int offset, size;

    resource = view->resource;
    if (resource->type != WINED3D_RTYPE_BUFFER)
    {
        FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
        return;
    }

    if (!gl_info->supported[ARB_CLEAR_BUFFER_OBJECT])
    {
        FIXME("OpenGL implementation does not support ARB_clear_buffer_object.\n");
        return;
    }

    format = view->format;
    if (format->id != WINED3DFMT_R32_UINT && format->id != WINED3DFMT_R32_SINT
            && format->id != WINED3DFMT_R32G32B32A32_UINT
            && format->id != WINED3DFMT_R32G32B32A32_SINT)
    {
        FIXME("Not implemented for format %s.\n", debug_d3dformat(format->id));
        return;
    }

    buffer = buffer_from_resource(resource);
    wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
    wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);

    get_buffer_view_range(buffer, &view->desc, format, &offset, &size);
    context_bind_bo(context, buffer->buffer_type_hint, buffer->buffer_object);
    GL_EXTCALL(glClearBufferSubData(buffer->buffer_type_hint, format->glInternal,
            offset, size, format->glFormat, format->glType, clear_value));
    checkGLcall("clear unordered access view");
}
void VisibilityExtractionDemo::run()
{
    const GLuint zero = 0;

    render(window, [&] (float deltaTime) {

        numberOfFrames++;
        frameInterval += deltaTime;

        if (frameInterval > 1.0f)
        {
            fps = numberOfFrames / frameInterval;

            std::cout << "FPS: " << fps << std::endl;

            numberOfFrames = 0;
            frameInterval = 0.0f;
        }

        if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) (rotY - deltaTime < 0)? rotY -= deltaTime + 6.283 : rotY -= deltaTime;
        if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) (rotY + deltaTime > 6.283)? rotY += deltaTime - 6.283 : rotY += deltaTime;
        if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) (rotX - deltaTime < 0)? rotX -= deltaTime + 6.283 : rotX -= deltaTime;
        if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) (rotX + deltaTime > 6.283)? rotX += deltaTime - 6.283 : rotX += deltaTime;
        if (glfwGetKey(window, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS) distance += deltaTime * 50;
        if (glfwGetKey(window, GLFW_KEY_PAGE_UP) == GLFW_PRESS) distance = max(distance - deltaTime * 50, 0.0f);
        if (glfwGetKey(window, GLFW_KEY_PERIOD) == GLFW_PRESS) scale += deltaTime*4;
        if (glfwGetKey(window, GLFW_KEY_COMMA) == GLFW_PRESS) scale = glm::max(scale - deltaTime*4, 0.01f);
        if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) {updateVisibilityMapLock = true; updateVisibilityMap = true;}
        if (glfwGetKey(window, GLFW_KEY_U) == GLFW_PRESS) updateVisibilityMapLock = false;
        if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) pingPongOff = false;
        if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS) pingPongOff = true;
        if (glfwGetKey(window, GLFW_KEY_F11) == GLFW_PRESS) { vsync = !vsync; vsync ? glfwSwapInterval(1) : glfwSwapInterval(0); vsync ? std::cout << "VSync enabled\n" : std::cout << "VSync disabled\n"; }

        // Render impostor geometry
        if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS)
        {
            renderBalls->setShaderProgram(&spRenderImpostor);
            renderBalls->texture("sortedVisibleIDsBuffer", tex_sortedVisibleIDsBuffer);
            result->update("maxRange", 1.0f);
            result->texture("tex", renderBalls->get("fragColor"));
        }
        // Render impostor geometry as disc
        if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS)
        {
            renderBalls->setShaderProgram(&spRenderDiscs);
            renderBalls->texture("sortedVisibleIDsBuffer", tex_sortedVisibleIDsBuffer);
            result->update("maxRange", 1.0f);
            result->texture("tex", renderBalls->get("fragColor"));
        }
        // Render faked geometry
        if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS)
        {
            renderBalls->setShaderProgram(&spRenderBalls);
            renderBalls->texture("sortedVisibleIDsBuffer", tex_sortedVisibleIDsBuffer);
            result->update("maxRange", 1.0f);
            result->texture("tex", renderBalls->get("fragColor"));
        }
        // Render instance IDs geometry
        if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS)
        {
            renderBalls->setShaderProgram(&spRenderBalls);
            renderBalls->texture("sortedVisibleIDsBuffer", tex_sortedVisibleIDsBuffer);
            result->update("maxRange", float(impSph->num_balls));
            result->texture("tex", renderBalls->get("InstanceID"));
        }
        if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        {
            if(animate)
            {
                animate = false;
                lastTime = glfwGetTime();
            }
            else
            {
                animate = true;
                glfwSetTime(lastTime);
            }
        }

        if (animate)
        {
            elapsedTime = glfwGetTime();
            if (elapsedTime > 628)
            {
                elapsedTime = 0;
                glfwSetTime(0);
            }
        }

        mat4 view = translate(mat4(1), vec3(0,0,-distance)) * eulerAngleXY(-rotX, -rotY);

        // reset the detected instance IDs
        glBindTexture(GL_TEXTURE_1D, tex_collectedIDsBuffer->getHandle());
        glTexImage1D(GL_TEXTURE_1D, 0, GL_R8UI, num_balls, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, zeros);
        //glBindTexture(GL_TEXTURE_1D, visibleIDsBuff->getHandle());
        //glTexImage1D(GL_TEXTURE_1D, 0, GL_R32UI, num_balls, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, &identityInstancesMap[0]);

        glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomBuff);
        glClearBufferSubData(GL_ATOMIC_COUNTER_BUFFER, GL_R32UI, 0, sizeof(GLuint), GL_RED_INTEGER, GL_UNSIGNED_INT, zero);

        renderBalls->clear(-1,-1,-1,-1); // the clear color may not interfere with the detected instance IDs
        renderBalls->clearDepth();
        renderBalls->update("scale", vec2(scale));
        renderBalls->update("view", view);
        renderBalls->update("probeRadius", probeRadius);
        renderBalls->run();


        // Depending on user input: sort out instances for the next frame or not,
        // or lock the current set of visible instances
        if(useAtomicCounters)
            if (updateVisibilityMap && !pingPongOff)
            {
                // the following shaders in detectVisible look at what has been written to the screen (framebuffer0)
                // better render the instance stuff to a texture and read from there
                collectSurfaceIDs->run();
                glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT|GL_BUFFER_UPDATE_BARRIER_BIT);
                glBeginQuery(GL_TIME_ELAPSED, timeQuery);
                computeSortedIDs->run(16,1,1); // 16 work groups * 1024 work items = 16384 atoms and IDs
                glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT|GL_SHADER_IMAGE_ACCESS_BARRIER_BIT|GL_BUFFER_UPDATE_BARRIER_BIT);
                glEndQuery(GL_TIME_ELAPSED);

                glGetQueryObjectuiv(timeQuery, GL_QUERY_RESULT, &queryTime);
                std::cout << "compute shader time: " << queryTime << std::endl;

                // Check buffer data
//                GLuint visibilityMapFromBuff[ImpostorSpheres::num_balls];
//                GLuint visibleIDsFromBuff[ImpostorSpheres::num_balls];
//                glBindTexture(GL_TEXTURE_1D, bufferTex->getHandle());
//                glGetTexImage(GL_TEXTURE_1D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, visibilityMapFromBuff);
//                glBindTexture(GL_TEXTURE_1D, visibleIDsBuff->getHandle());
//                glGetTexImage(GL_TEXTURE_1D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, visibleIDsFromBuff);

                //get the value of the atomic counter
                glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomBuff);
                GLuint* counterVal = (GLuint*) glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),  GL_MAP_READ_BIT );
                glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);

                impSph->instancesToRender = *counterVal;
                std::cout << "Number of visible instances by atomic Counter: " << *counterVal << std::endl;

                updateVisibilityMap = false;
            }else
            {
                if(!updateVisibilityMapLock)
                {
                    // ToDo
                    // instead of uploading the data, swap the buffer
                    glBindTexture(GL_TEXTURE_1D, tex_sortedVisibleIDsBuffer->getHandle());
                    glTexImage1D(GL_TEXTURE_1D, 0, GL_R32UI, num_balls, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, &identityInstancesMap[0]);
                    impSph->instancesToRender = impSph->num_balls;
                    updateVisibilityMap = true; // sort out every other frame
                }
            }
        else
            if (updateVisibilityMap && !pingPongOff)
            {
                collectSurfaceIDs->run();
                // detect visible instances
                glBeginQuery(GL_TIME_ELAPSED, timeQuery);
                GLuint visibilityMapFromBuff[impSph->num_balls];
                glBindTexture(GL_TEXTURE_1D, tex_collectedIDsBuffer->getHandle());
                glGetTexImage(GL_TEXTURE_1D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, visibilityMapFromBuff);

                // copy visible instance information to a vector with size = num_balls
                int num_vis = 0;
                std::vector<GLint> newMap;
                newMap.resize(num_balls);
                for (int i = 0; i < num_balls; i++)
                {
                    newMap[i] = (int)visibilityMapFromBuff[i];
                    if(visibilityMapFromBuff[i] != 0)
                        num_vis++;
                }
                glEndQuery(GL_TIME_ELAPSED);
                glGetQueryObjectuiv(timeQuery, GL_QUERY_RESULT, &queryTime);
                std::cout << "cpu time: " << queryTime << std::endl;

                // print number of visible instances
                std::cout << "Number of visible instances: " << num_vis << std::endl;
                impSph->updateVisibilityMap(newMap);
                updateVisibilityMap = false;
            }else
            {
                if(!updateVisibilityMapLock)
                {
                    impSph->updateVisibilityMap(mapAllVisible);
                    updateVisibilityMap = true; // sort out every other frame
                }
            }

        result->clear(num_balls,num_balls,num_balls,num_balls);
        result->run();
    });
}
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL43_nglClearBufferSubData(JNIEnv *__env, jclass clazz, jint target, jint internalformat, jlong offset, jlong size, jint format, jint type, jlong dataAddress, jlong __functionAddress) {
	const GLvoid *data = (const GLvoid *)(intptr_t)dataAddress;
	glClearBufferSubDataPROC glClearBufferSubData = (glClearBufferSubDataPROC)(intptr_t)__functionAddress;
	UNUSED_PARAMS(__env, clazz)
	glClearBufferSubData(target, internalformat, (GLintptr)offset, (GLsizeiptr)size, format, type, data);
}
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL43_nglClearBufferSubData__IIJJIIJ(JNIEnv *__env, jclass clazz, jint target, jint internalformat, jlong offset, jlong size, jint format, jint type, jlong dataAddress) {
    glClearBufferSubDataPROC glClearBufferSubData = (glClearBufferSubDataPROC)tlsGetFunction(871);
    intptr_t data = (intptr_t)dataAddress;
    UNUSED_PARAM(clazz)
    glClearBufferSubData(target, internalformat, (intptr_t)offset, (intptr_t)size, format, type, data);
}
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL43_nglClearBufferSubData(JNIEnv *env, jclass clazz, jint target, jint internalformat, jlong offset, jlong size, jint format, jint type, jlong data, jlong function_pointer) {
	const GLvoid *data_address = (const GLvoid *)(intptr_t)data;
	glClearBufferSubDataPROC glClearBufferSubData = (glClearBufferSubDataPROC)((intptr_t)function_pointer);
	glClearBufferSubData(target, internalformat, offset, size, format, type, data_address);
}
示例#11
0
void GLBufferObject::Clear( GLenum internalformat, int offset, int size, GLenum format, GLenum type, const void* data )
{
	Bind();
	glClearBufferSubData(target, internalformat, offset, size, format, type, data);
	Unbind();
}
示例#12
0
PIGLIT_GL_TEST_CONFIG_END


void
piglit_init(int argc, char **argv)
{
	bool pass = true;
	const int buffer_size = 1<<20;
	unsigned int buffer;
	static const char *const data_7f   = "\x7f\x7f\x7f\x7f";
	static const char *const data_zero = "\x00\x00\x00\x00";
	static const char *const data_one  = "\xff\xff\xff\xff";
	static const char *const data_init = "\xff\xff\xff\xff"
					     "\xff\xff\xff\xff"
					     "\x00\x00\x00\x00"
					     "\x00\x00\x00\x00"
					     "\x55\x55\x55\x55"
					     "\x55\x55\x55\x55"
					     "\xaa\xaa\xaa\xaa"
					     "\xaa\xaa\xaa\xaa"
					     "\xff\x00\xff\x00"
					     "\xff\x00\xff\x00"
					     "\x00\xff\x00\xff"
					     "\x00\xff\x00\xff"
					     "\x91\xcc\x45\x36"
					     "\xd3\xe4\xe3\x5b"
					     "\x79\x1e\x21\x39"
					     "\xa8\xfa\x69\x6a";


	piglit_require_extension("GL_ARB_clear_buffer_object");

	glGenBuffers(1, &buffer);
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	glBufferData(GL_ARRAY_BUFFER, buffer_size, NULL, GL_STREAM_READ);
	fill_array_buffer(64, data_init);

	/* Buffer contents:
	 * xx xx xx xx xx xx xx xx
	 */
	glClearBufferSubData(GL_ARRAY_BUFFER, GL_RGBA8, 1*buffer_size/8,
			buffer_size/4, GL_RGBA, GL_UNSIGNED_BYTE, data_7f);
	/* xx 7f 7f xx xx xx xx xx */
	glClearBufferSubData(GL_ARRAY_BUFFER, GL_RGBA8, 2*buffer_size/8,
			buffer_size/4, GL_RGBA, GL_UNSIGNED_BYTE, data_zero);
	/* xx 7f 00 00 xx xx xx xx */
	glClearBufferSubData(GL_ARRAY_BUFFER, GL_RGBA8, 3*buffer_size/8,
			buffer_size/4, GL_RGBA, GL_UNSIGNED_BYTE, data_one);
	/* xx 7f 00 FF FF xx xx xx */

	pass = check_array_buffer_sub_data(0, buffer_size/8,
			64, data_init) && pass;
	pass = check_array_buffer_sub_data(1*buffer_size/8, buffer_size/8,
			4, data_7f) && pass;
	pass = check_array_buffer_sub_data(2*buffer_size/8, buffer_size/8,
			4, data_zero) && pass;
	pass = check_array_buffer_sub_data(3*buffer_size/8, buffer_size/4,
			4, data_one) && pass;
	pass = check_array_buffer_sub_data(5*buffer_size/8, 3*buffer_size/8,
			64, data_init) && pass;

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glDeleteBuffers(1, &buffer);

	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;

	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
}
示例#13
0
void cullindirect_app::render(double currentTime)
{
    static const GLfloat farplane[] = { 1.0f };
    static float lastTime = 0.0f;
    static int frames = 0;
    float nowTime = float(currentTime);
    int i;

    // Set viewport and clear
    glViewport(0, 0, info.windowWidth, info.windowHeight);
    glClearBufferfv(GL_COLOR, 0, sb7::color::Black);
    glClearBufferfv(GL_DEPTH, 0, farplane);

    // Bind and clear atomic counter
    glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, buffers.parameters);
    glClearBufferSubData(GL_ATOMIC_COUNTER_BUFFER, GL_R32UI, 0, sizeof(GLuint), GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);

    // Bind shader storage buffers
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffers.drawCandidates);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffers.drawCommands);

    // Bind model matrix UBO and fill with data
    glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffers.modelMatrices);
    vmath::mat4* pModelMatrix = (vmath::mat4*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 1024 * sizeof(vmath::mat4), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
    
    for (i = 0; i < 1024; i++)
    {
        float f = float(i) / 127.0f + nowTime * 0.025f;
        float g = float(i) / 127.0f;
        const vmath::mat4 model_matrix = vmath::translate(70.0f * vmath::vec3(sinf(f * 3.0f), cosf(f * 5.0f), cosf(f * 9.0f))) *
                                         vmath::rotate(nowTime * 140.0f, vmath::normalize(vmath::vec3(sinf(g * 35.0f), cosf(g * 75.0f), cosf(g * 39.0f))));
        pModelMatrix[i] = model_matrix;
    }

    glUnmapBuffer(GL_UNIFORM_BUFFER);

    // Bind view + projection matrix UBO and fill
    glBindBufferBase(GL_UNIFORM_BUFFER, 1, buffers.transforms);
    TransformBuffer* pTransforms = (TransformBuffer*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(TransformBuffer), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

    float t = nowTime * 0.1f;

    const vmath::mat4 view_matrix = vmath::lookat(vmath::vec3(150.0f * cosf(t), 0.0f, 150.0f * sinf(t)),
                                                  vmath::vec3(0.0f, 0.0f, 0.0f),
                                                  vmath::vec3(0.0f, 1.0f, 0.0f));
    const vmath::mat4 proj_matrix = vmath::perspective(50.0f,
                                                       (float)info.windowWidth / (float)info.windowHeight,
                                                       1.0f,
                                                       2000.0f);

    pTransforms->view_matrix = view_matrix;
    pTransforms->proj_matrix = proj_matrix;
    pTransforms->view_proj_matrix = proj_matrix * view_matrix;

    glUnmapBuffer(GL_UNIFORM_BUFFER);

    // Bind the culling compute shader and dispatch it
    glUseProgram(programs.cull);
    glDispatchCompute(CANDIDATE_COUNT / 16, 1, 1);

    // Barrier
    glMemoryBarrier(GL_COMMAND_BARRIER_BIT);

    // Get ready to render
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glBindVertexArray(object.get_vao());

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    // Bind indirect command buffer and parameter buffer
    glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffers.drawCommands);
    glBindBuffer(GL_PARAMETER_BUFFER_ARB, buffers.parameters);

    glUseProgram(programs.draw);

    // Draw
    glMultiDrawArraysIndirectCountARB(GL_TRIANGLES, 0, 0, CANDIDATE_COUNT, 0);

    // Update overlay
    if (nowTime > (lastTime + 0.25f))
    {
        fps = float(frames) / (nowTime - lastTime);
        frames = 0;
        lastTime = nowTime;
    }

    glDisable(GL_CULL_FACE);
    updateOverlay();

    frames++;
}