| 67 | } |
| 68 | |
| 69 | void EngineGL33::FlushQueue(QueueGL33& queue, int index) |
| 70 | { |
| 71 | TriQueue& triq = queue._tri[index]; |
| 72 | int n = triq._triangleQueue.Size(); |
| 73 | if (n > 0) |
| 74 | { |
| 75 | // Upload the deferred vertex range before any draw consumes it. |
| 76 | UploadPendingVertices(); |
| 77 | |
| 78 | if (index == MaxTriQueues - 1) |
| 79 | FlushAllQueues(queue, index); |
| 80 | |
| 81 | ApplyPassState(triq._texture, triq._level, Poseidon::render::SplitLegacy(triq._special), triq._passId, |
| 82 | PipelineVertexInput::Screen); |
| 83 | |
| 84 | if (!_vaoScreen || !_vbo || !_ibo) |
| 85 | { |
| 86 | triq._triangleQueue.Clear(); |
| 87 | return; |
| 88 | } |
| 89 | |
| 90 | // SelectVertexShader's VAO bind is cached on shader change only, |
| 91 | // so a same-shader call doesn't rebind. Combined with other |
| 92 | // paths that leave a different VAO bound (e.g. DrawSectionTL's |
| 93 | // mesh VAO), we may arrive here with the wrong VAO. Bind |
| 94 | // _vaoScreen explicitly — TLVertex layout matches it. |
| 95 | GL33Bind::Vao(_vaoScreen); |
| 96 | // This direct VAO bind desyncs the VAO from _vertexShaderSel, which the |
| 97 | // effort-06 ApplyPipeline pass-dedup cache assumes stay paired (SelectVertexShader |
| 98 | // owns both). Without invalidating, the next 3D draw's identical descriptor |
| 99 | // short-circuits ApplyPipeline -> SelectVertexShader is skipped -> the mesh draws |
| 100 | // through this 2D _vaoScreen layout -> garbage vertices (the Single Missions |
| 101 | // notebook rendered invisible). Invalidate so the next ApplyPipeline re-selects |
| 102 | // its shader and rebinds the mesh VAO. |
| 103 | InvalidatePipelineCache(); |
| 104 | |
| 105 | // Upload indices |
| 106 | int indexOffset = 0; |
| 107 | int ibSize = n * sizeof(WORD); |
| 108 | Poseidon::render::ibo::BindOnActiveVao(_ibo); |
| 109 | |
| 110 | if (n + queue._indexBufferUsed <= IndexBufferLength && !queue._firstIndex) |
| 111 | { |
| 112 | indexOffset = queue._indexBufferUsed; |
| 113 | glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexOffset * sizeof(WORD), ibSize, triq._triangleQueue.Data()); |
| 114 | } |
| 115 | else |
| 116 | { |
| 117 | queue._firstIndex = false; |
| 118 | indexOffset = 0; |
| 119 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, IndexBufferLength * sizeof(WORD), nullptr, GL_DYNAMIC_DRAW); |
| 120 | glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, ibSize, triq._triangleQueue.Data()); |
| 121 | } |
| 122 | queue._indexBufferUsed = indexOffset + n; |
| 123 | |
| 124 | // Bind vertex buffer |
| 125 | glBindBuffer(GL_ARRAY_BUFFER, _vbo); |
| 126 |
nothing calls this directly
no test coverage detected