{
  "choices": [
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000001",
      "question": "<p>A compute shader runs inside the normal graphics pipeline, alongside vertex and fragment shaders. True or false?</p>",
      "answers": [
        "False — compute shaders run outside the graphics pipeline as general-purpose GPU programs",
        "True — compute shaders are an optional extra stage after the fragment shader",
        "True — compute shaders replace the vertex shader when geometry is not needed",
        "False — compute shaders run on the CPU using SIMD intrinsics, not the GPU"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000002",
      "question": "<p>What is the minimum OpenGL version required to use compute shaders?</p>",
      "answers": [
        "OpenGL 4.3",
        "OpenGL 3.3",
        "OpenGL 4.0",
        "OpenGL 4.6"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000003",
      "question": "<p>Which OpenGL call launches a compute shader instead of issuing a draw call?</p>",
      "answers": [
        "glDispatchCompute(groupsX, groupsY, groupsZ)",
        "glDrawArraysCompute(GL_COMPUTE_SHADER, 0, count)",
        "glExecuteCompute(numThreads)",
        "glBeginCompute() ... glEndCompute()"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000004",
      "question": "<p>For 100,000 particles with layout(local_size_x = 256) in the shader, how many work groups must be dispatched?</p>",
      "answers": [
        "391 — computed as ceil(100000 / 256)",
        "256 — one work group per thread",
        "400 — rounded up to the nearest hundred",
        "100000 — one work group per particle"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000005",
      "question": "<p>How does each compute shader thread know which particle it should update?</p>",
      "answers": [
        "It reads gl_GlobalInvocationID.x, which gives a unique index per thread",
        "It reads gl_VertexID, which increments per work group",
        "It reads gl_FragCoord.x, which maps to a pixel position",
        "The CPU writes a per-thread index into a uniform before dispatch"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000006",
      "question": "<p>After glDispatchCompute(), why must glMemoryBarrier() be called before using the SSBO in a draw call?</p>",
      "answers": [
        "The GPU does not guarantee SSBO writes are visible to other shader stages until a memory barrier is issued",
        "glMemoryBarrier() flushes the command queue so the CPU can read the SSBO",
        "glMemoryBarrier() resets the SSBO binding point so the draw call can bind it",
        "glMemoryBarrier() is needed only when the SSBO is larger than 64 KB"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000007",
      "question": "<p>Why does ComputeShader inherit from Shader rather than standing alone?</p>",
      "answers": [
        "A compute shader is still an OpenGL program object and shares Bind(), Unbind(), and all setUniform*() methods unchanged",
        "Inheritance is required by the OpenGL specification for compute programs",
        "ComputeShader reuses the vertex and fragment compilation paths from Shader",
        "Shader provides a thread-safe dispatch queue that ComputeShader depends on"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000008",
      "question": "<p>Which shader stage constant is passed to glCreateShader() when compiling a compute shader?</p>",
      "answers": [
        "GL_COMPUTE_SHADER",
        "GL_VERTEX_SHADER",
        "GL_GEOMETRY_SHADER",
        "GL_TESS_EVALUATION_SHADER"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000009",
      "question": "<p>Unlike the base Shader class, ComputeShader::ReadFile does not split the source into sections. Why?</p>",
      "answers": [
        "A compute shader is a single continuous GLSL block — there are no vertex or fragment sections to separate",
        "The GLSL pre-processor handles section splitting automatically for compute shaders",
        "ReadFile is not needed at all; compute source is always embedded as a string literal",
        "ComputeShader uses a binary SPIR-V format instead of text GLSL"
      ]
    },
    {
      "subContentId": "aaaaaaaa-0001-0000-0000-000000000010",
      "question": "<p>After glLinkProgram(), what should be done with the individual shader object returned by Compile()?</p>",
      "answers": [
        "Call glDeleteShader() — the shader is baked into the program after linking and the object is no longer needed",
        "Keep it alive; deleting it will also delete the linked program",
        "Call glDetachShader() but do not delete it, to allow recompilation",
        "Cache it as a member variable so it can be reattached after glUseProgram()"
      ]
    }
  ],
  "overallFeedback": [
    {
      "from": 0,
      "to": 49,
      "feedback": "Keep reviewing the concepts."
    },
    {
      "from": 50,
      "to": 74,
      "feedback": "Good effort — a few gaps to address."
    },
    {
      "from": 75,
      "to": 100,
      "feedback": "Great work!"
    }
  ],
  "behaviour": {
    "autoContinue": false,
    "timeoutCorrect": 2000,
    "timeoutWrong": 3000,
    "soundEffectsEnabled": true,
    "enableRetry": true,
    "enableSolutionsButton": false,
    "passPercentage": 100
  },
  "l10n": {
    "nextButtonLabel": "Next question",
    "showSolutionButtonLabel": "Show solution",
    "retryButtonLabel": "Retry",
    "solutionViewTitle": "Solution list"
  }
}