From 9caf4407466c6291f1e6d3900a3cd9392ae6420e Mon Sep 17 00:00:00 2001 From: Seiji Emery Date: Tue, 4 Aug 2015 12:53:23 -0700 Subject: [PATCH] basic shader sort-of working (sip) --- tests/gpu-test/CMakeLists.txt | 2 + tests/gpu-test/src/gputest_shaders.h | 48 ++++ tests/gpu-test/src/main.cpp | 334 +++++++++++++++++++-------- 3 files changed, 287 insertions(+), 97 deletions(-) create mode 100644 tests/gpu-test/src/gputest_shaders.h diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index 9f423e3645..c4aaf73eb8 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -1,6 +1,8 @@ set(TARGET_NAME gpu-test) +AUTOSCRIBE_SHADER_LIB(gpu) + # This is not a testcase -- just set it up as a regular hifi project setup_hifi_project(Quick Gui OpenGL) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") diff --git a/tests/gpu-test/src/gputest_shaders.h b/tests/gpu-test/src/gputest_shaders.h new file mode 100644 index 0000000000..911ae4b624 --- /dev/null +++ b/tests/gpu-test/src/gputest_shaders.h @@ -0,0 +1,48 @@ +// +// gputest_shaders.h +// hifi +// +// Created by Seiji Emery on 8/3/15. +// +// + +#ifndef hifi_gputest_shaders_h +#define hifi_gputest_shaders_h + +const std::string & basicVertexShader () { + static std::string src = R"( + +// attribute vec3 position; +// attribute vec3 normal; + + varying vec3 normal; + + void main (void) { +// gl_Position = gl_ModelViewProjectionMatrix * vec4(position.xyz, 1.0); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + normal = gl_Normal; + } + + )"; + return src; +} + +const std::string & basicFragmentShader () { + static std::string src = R"( + #version 400 + + varying vec3 normal; + + void main(void) { + gl_FragColor.rgb = vec3(0.7, 0.2, 0.5) + gl_FragCoord.xyz * 0.2; + + vec3 diffuse = vec3(0.7, 0.2, 0.5); + vec3 light_normal = vec3(0.5, -0.5, 0.7); + + gl_FragColor.rgb = diffuse * dot(light_normal, normal); + } + + )"; + return src; +} +#endif diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index a4a68c1d84..a0dabc2516 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -38,13 +38,12 @@ #include #include #include - - #include - - #include +#include "gputest_shaders.h" + + class RateCounter { std::vector times; QElapsedTimer timer; @@ -81,15 +80,6 @@ public: } }; -const char * basicVS = -" varying vec3 pos; " -" void main(void) { " -" gl_Position.xyz = pos; " -" } "; -const char * basicFS = -" void main(void) { " -" gl_FragColor.xyz = vec3(0.7, 0.2, 0.5); " -" } "; const QString& getQmlDir() { static QString dir; @@ -102,6 +92,170 @@ const QString& getQmlDir() { return dir; } +#define MOVE_PARAM(name) decltype(name) && name + +struct BasicModel { + gpu::PipelinePointer pipeline; +// gpu::BufferPointer vertexBuffer; +// gpu::BufferPointer indexBuffer; +// gpu::BufferPointer normalBuffer; + + gpu::BufferView vertices; + gpu::BufferView normals; + gpu::BufferPointer indices; + + gpu::Stream::FormatPointer format; + + BasicModel (MOVE_PARAM(pipeline), MOVE_PARAM(vertices), MOVE_PARAM(normals), MOVE_PARAM(indices), MOVE_PARAM(format)) + : pipeline(pipeline), vertices(vertices), normals(normals), indices(indices), format(format) {} + +// BasicModel (gpu::PipelinePointer && pipeline, gpu::BufferPointer && buffer, gpu::Stream::FormatPointer && format) +// : pipeline(pipeline), buffer(buffer), format(format) {} +}; +typedef std::shared_ptr BasicModelPointer; +#undef MOVE_PARAM + +BasicModelPointer makeCube () { + // Axis-aligned cube, facing the user at +z + // coords == binary mapping of each index, with z inverted (front face faces camera, + // instead of away from the camera) + // + // -x,+y,-z ----------- +x,+y,-z + // ___--- | ___--- | + // -x,+y,+z --------- +x,+y,+z | + // | | | | + // | | | | + // | | | | + // | | | | + // | -x,-y,-z ------|---- +x,-y,-z + // | ___--- | ___---- + // -x,-y,+z --------- +x,-y,+z + // + float s = 1.0f; + const glm::vec3 raw_verts[8] = { + // x, y, z + { -s, -s, +s }, // 0b000 0x0 + { +s, -s, +s }, // 0b001 0x1 + { -s, +s, +s }, // 0b010 0x2 + { +s, +s, +s }, // 0b011 0x3 + { -s, -s, -s }, // 0b100 0x4 + { +s, -s, -s }, // 0b101 0x5 + { -s, +s, -s }, // 0b110 0x6 + { +s, +s, -s } // 0b111 0x7 + }; + const glm::vec3 raw_normals[6] = { + { 0.0f, 0.0f, +1.0f }, // x > 0: 1, 3, 5, 7 (N 0) + { 0.0f, 0.0f, -1.0f }, // x < 0: 0, 2, 4, 6 (N 1) + { 0.0f, +1.0f, 0.0f }, // y > 0: 2, 3, 6, 7 (N 2) + { 0.0f, -1.0f, 0.0f }, // y < 0: 0, 1, 4, 5 (N 3) + { +1.0f, 0.0f, 0.0f }, // z > 0: 0, 1, 2, 3 (N 4) + { -1.0f, 0.0f, 0.0f } // z < 0: 4, 5, 6, 7 (N 5) + }; + + const glm::vec3 cube_verts[24] = { + raw_verts[1], raw_verts[3], raw_verts[5], raw_verts[7], + raw_verts[0], raw_verts[2], raw_verts[4], raw_verts[6], + raw_verts[2], raw_verts[3], raw_verts[6], raw_verts[7], + raw_verts[0], raw_verts[1], raw_verts[4], raw_verts[5], + raw_verts[0], raw_verts[1], raw_verts[2], raw_verts[3], + raw_verts[4], raw_verts[5], raw_verts[6], raw_verts[7] + }; + const glm::vec3 cube_normals[24] = { + raw_normals[0], raw_normals[0], raw_normals[0], raw_normals[0], + raw_normals[1], raw_normals[1], raw_normals[1], raw_normals[1], + raw_normals[2], raw_normals[2], raw_normals[2], raw_normals[2], + raw_normals[3], raw_normals[3], raw_normals[3], raw_normals[3], + raw_normals[4], raw_normals[4], raw_normals[4], raw_normals[4], + raw_normals[5], raw_normals[5], raw_normals[5], raw_normals[5] + }; + + int16_t cube_indices_tris[36]; + for (int i = 0, k = 0; i < 36; k += 4) { + cube_indices_tris[i++] = k + 0; + cube_indices_tris[i++] = k + 3; + cube_indices_tris[i++] = k + 1; + cube_indices_tris[i++] = k + 0; + cube_indices_tris[i++] = k + 2; + cube_indices_tris[i++] = k + 3; + } + +// const int16_t cube_indices_tris[36] { +// 0, 3, 1, 0, 2, 3, +// }; + +// const glm::vec3 cube_normals[] = { +// { 0.0f, 0.0f, 1.0f }, +// { 0.0f, 0.0f, 1.0f }, +// { 0.0f, 0.0f, 1.0f }, +// { 0.0f, 0.0f, 1.0f }, +// { -1.0f, 0.0f, 0.0f }, +// { -1.0f, 0.0f, 0.0f }, +// { -1.0f, 0.0f, 0.0f }, +// { -1.0f, 0.0f, 0.0f }, +// }; +// const int16_t cube_indices[] = { +// 3, 1, 0, 2, 3, 0, +// 6, 2, 0, 4, 6, 0, +// }; + + gpu::Stream::FormatPointer format = std::make_shared(); + format->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element::VEC3F_XYZ); + format->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, gpu::Element::VEC3F_XYZ); + + auto vertexBuffer = std::make_shared(24 * sizeof(glm::vec3), (gpu::Byte*)cube_verts); + auto normalBuffer = std::make_shared(24 * sizeof(glm::vec3), (gpu::Byte*)cube_normals); + gpu::BufferPointer indexBuffer = std::make_shared(36 * sizeof(int16_t), (gpu::Byte*)cube_indices_tris); + + auto positionElement = format->getAttributes().at(gpu::Stream::POSITION)._element; + auto normalElement = format->getAttributes().at(gpu::Stream::NORMAL)._element; + + gpu::BufferView vertexView { vertexBuffer, positionElement }; + gpu::BufferView normalView { normalBuffer, normalElement }; + + // Create shaders + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(basicVertexShader())); + auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(basicFragmentShader())); + auto shader = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); + + gpu::Shader::BindingSet bindings; + + if (!gpu::Shader::makeProgram(*shader, bindings)) { + printf("Could not compile shader\n"); + if (!vs) + printf("bad vertex shader\n"); + if (!fs) + printf("bad fragment shader\n"); + if (!shader) + printf("bad shader program\n"); + exit(-1); + } + + auto state = std::make_shared(); +// state->setAntialiasedLineEnable(true); + state->setMultisampleEnable(true); + state->setDepthTest({ true }); + auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(shader, state)); + + return std::make_shared( + std::move(pipeline), + std::move(vertexView), + std::move(normalView), + std::move(indexBuffer), + std::move(format) + ); +} + +void renderCube(gpu::Batch & batch, const BasicModel & cube) { + + batch.setPipeline(cube.pipeline); + batch.setInputFormat(cube.format); + batch.setInputBuffer(gpu::Stream::POSITION, cube.vertices); + batch.setInputBuffer(gpu::Stream::NORMAL, cube.normals); + batch.setIndexBuffer(gpu::INT16, cube.indices, 0); +// batch.drawIndexed(gpu::TRIANGLES, 12); + batch.draw(gpu::TRIANGLES, 24); +} + // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT @@ -111,9 +265,7 @@ class QTestWindow : public QWindow { gpu::ContextPointer _context; gpu::PipelinePointer _pipeline; - gpu::BufferPointer _buffer; - gpu::Stream::FormatPointer _format; - + BasicModelPointer _cubeModel; //TextRenderer* _textRenderer[4]; RateCounter fps; @@ -154,63 +306,10 @@ public: batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 1.0, 0.0, 0.5, 1.0 }); _context->render(batch); - // Create default shaders + _cubeModel = makeCube(); - std::string vsSource (basicVS); - std::string fsSource (basicFS); - - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(vsSource)); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(fsSource)); - auto shader = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); - - gpu::Shader::BindingSet bindings; - if (!gpu::Shader::makeProgram(*shader, bindings)) { - printf("Could not compile shader"); - exit(-1); - } - -// auto shader = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - - auto state = std::make_shared(); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(shader, state)); - - float z = 10.0f; - const glm::vec3 vertices[] = { - { -1.0f, 1.0f, z }, - { 1.0f, -1.0f, z }, - { -1.0f, -1.0f, z } - }; - _buffer = std::make_shared(sizeof(vertices), (const gpu::Byte*)vertices); - _format = std::make_shared(); - _format->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - - -// { -// QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); -// logger->initialize(); // initializes in the current context, i.e. ctx -// logger->enableMessages(); -// connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { -// qDebug() << debugMessage; -// }); -// // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); -// } -// qDebug() << (const char*)glGetString(GL_VERSION); - - //_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); - //_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, - // TextRenderer::SHADOW_EFFECT); - //_textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, - // false, TextRenderer::OUTLINE_EFFECT); - //_textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); - -// glEnable(GL_BLEND); -// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -// glClearColor(0.2f, 0.2f, 0.2f, 1); -// glDisable(GL_DEPTH_TEST); - - makeCurrent(); - - _context->syncCache(); +// makeCurrent(); +// _context->syncCache(); setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); @@ -257,41 +356,81 @@ void QTestWindow::draw() { gpu::Batch batch; static int frameNum = 0; frameNum++; - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 1.0, float(frameNum % 60)/60.0f, 0.5, 1.0 }); -// _context->render(batch); + float t = frameNum / 120.0f; + + float k = (frameNum % 120) / 120; + float ks = glm::sin(glm::pi() * 2.0f * k); + + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 0.1, 0.1, 0.1, 1.0 }); +// batch.clearDepthFramebuffer(-10000.0f); +// batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 1.0, float(frameNum % 60)/60.0f, 0.5, 1.0 }); + + batch.setViewportTransform({ 0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio() }); -//// batch.clear(); -// batch.setViewportTransform({ 0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio() }); -// - glm::quat cubeOrientation; -// - batch.setViewTransform(Transform()); - batch.setProjectionTransform(glm::mat4()); -// batch.setProjectionTransform(_viewFrustrum->getProjection()); - batch.setModelTransform(Transform().setRotation(cubeOrientation)); - batch.setPipeline(_pipeline); - batch.setInputBuffer(gpu::Stream::POSITION, _buffer, 0, 3); - batch.setInputFormat(_format); - batch.draw(gpu::TRIANGLES, 3); + + // camera at x: 5 * sin(t) + // y: 1, + // z: +10 + // obj at (0, 0, 0) + // camera is looking at obj (using glm::lookAt) + + glm::vec3 up { 0.0f, 1.0f, 0.0f }; + glm::vec3 unitscale { 1.0f }; + + float cube_angle = 0.0f; +// glm::vec3 cube_pos { +// 0.0f, +// 0.0f, +// 0.0f +// }; + glm::vec3 cube_pos { + 20.0f * cos(t * 5.0f), + 10.0f * sin(t * 2.5f) + 1.0f, + -15.0f + float(int(t * int(1e3)) % int(1e4)) / 1e3 + }; + + // float cube_angle = 360.0f * k * 1.25 + 120.0f * k * 0.1f; +// glm::quat cube_rotation = glm::angleAxis(glm::radians(cube_angle), up); + glm::quat cube_rotation; + Transform cube_transform { cube_rotation, unitscale, cube_pos }; + +// glm::vec3 cam_pos { 0.0f, 0.0f, -10.0f }; + glm::vec3 cam_pos { 5.0f * sin(t * 0.1f), 1.0f, -10.0f }; + glm::quat cam_rotation = glm::quat_cast(glm::lookAt(cam_pos, cube_pos, up)); + cam_rotation.w = -cam_rotation.w; + Transform cam_transform { cam_rotation, unitscale, cam_pos }; + + float fov_degrees = 120.0f; +// float aspect_ratio = _size.height() / (_size.width() || 1.0f); + float aspect_ratio = 16.0f / 9.0f; + float near_clip = 0.1f; + float far_clip = 1000.0f; + auto projection = glm::perspective(glm::radians(fov_degrees), aspect_ratio, near_clip, far_clip); + + batch.setProjectionTransform(projection); + batch.setViewTransform(cam_transform); + batch.setModelTransform(cube_transform); + + batch.setModelTransform(Transform().setTranslation({ 20.0f * cos(t * 5.0f), 10.0f * sin(t * 2.5f + 1.0f), -15.0f + float(int(t * 1000) % 10000) / 1e3f})); +// batch.setPipeline(_pipeline); +// batch.setInputBuffer(gpu::Stream::POSITION, _buffer, 0, 3); +// batch.setInputFormat(_format); +// batch.draw(gpu::TRIANGLES, 3); + + renderCube(batch, *_cubeModel); _context->render(batch); // //// gpu::Stream::Format format; //// format.setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::Vec3, gpu::FLOAT, gpu::XYZ)); //// batch.setInputBuffer(gpu::Stream::POSITION, _trianglePosBuffer, ) -// -// -//// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -//// glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); -// -//// _context->swapBuffers(this); -//// glFinish(); -// + _qGlContext->swapBuffers(this); + // glFinish(); fps.increment(); if (fps.elapsed() >= 2.0f) { - qDebug() << "FPS: " << fps.rate(); // This prints out the frames per 2 secs (ie. half of the actual fps) bug...? + qDebug() << "FPS: " << fps.rate() * 2.0f; // This prints out the frames per 2 secs (ie. half of the actual fps) bug...? fps.reset(); } } @@ -300,7 +439,8 @@ int main(int argc, char** argv) { QGuiApplication app(argc, argv); QTestWindow window; QTimer timer; - timer.setInterval(1000 / 120.0f); +// timer.setInterval(1000 / 120.0f); + timer.setInterval(0); app.connect(&timer, &QTimer::timeout, &app, [&] { window.draw(); });