I want you to perform a focused GPU/render-pipeline optimization pass on the GLDoze desktop renderer.

Current state:

* GLDoze is a C++/OpenGL desktop/UI environment.
* We already implemented:

  * scissor-based clipping
  * draw batching
  * occlusion culling
* These changes produced a substantial real-world improvement, so preserve the existing architecture and behavior.
* Do NOT remove or redesign working optimizations unless there is a clearly demonstrated reason.
* Maintain visual output and existing functionality exactly.
* Avoid broad unrelated refactors.

Your task is to investigate and implement the next set of renderer optimizations where they are genuinely beneficial.

Primary targets:

1. Dirty-region / damage tracking

Implement proper dirty-region tracking so GLDoze does not unnecessarily redraw unchanged portions of the desktop.

Requirements:

* Windows/widgets should invalidate only the regions that actually change.
* Track damaged rectangles per frame.
* Merge/coalesce overlapping or nearby dirty rectangles where sensible.
* Combine dirty-region rendering with the existing scissor system.
* Avoid turning many tiny dirty rectangles into excessive draw overhead.
* Support full redraw fallback when necessary.
* Window movement, resize, expose/uncover, animations, cursor changes, text changes, and similar cases must invalidate the correct regions.
* Ensure occlusion culling still behaves correctly with dirty regions.
* Add useful profiler statistics:

  * total screen area
  * dirty pixel/area percentage
  * dirty rectangle count
  * merged rectangle count
  * full-redraw count

2. Texture atlasing

Investigate and implement texture atlases for frequently used small UI textures where worthwhile.

Candidates include:

* icons
* glyphs/font textures
* small UI sprites
* repeated decorative assets

Requirements:

* Reduce texture binds and state changes.
* Do not force large images, arbitrary user images, video frames, or unsuitable textures into the atlas.
* Use sensible atlas page sizes and support multiple pages if required.
* Store UV coordinates cleanly.
* Handle lifetime management and removal safely.
* Avoid unnecessary atlas rebuilds.
* Preserve filtering and visual quality.
* If the font renderer already has a glyph cache/atlas, improve or integrate it rather than creating a conflicting duplicate system.
* Add profiling for:

  * texture binds/frame
  * atlas page count
  * atlas occupancy
  * atlas uploads/frame
  * atlas misses

3. Persistent mapped GPU buffers

Investigate replacing hot-path dynamic VBO/instance-buffer updates with persistent mapped buffers using modern OpenGL where supported.

Prefer:

* glBufferStorage
* GL_MAP_PERSISTENT_BIT
* GL_MAP_WRITE_BIT
* appropriate coherent or explicit flush strategy

Requirements:

* Avoid CPU/GPU synchronization stalls.
* Implement a ring-buffer or segmented-frame strategy.
* Use fences only where actually required.
* Never overwrite data still in use by the GPU.
* Provide a safe fallback for hardware/drivers that do not support the required feature.
* Do not blindly convert static buffers that do not benefit.
* Measure whether persistent mapping improves the current batching pipeline before spreading it everywhere.

Add profiler metrics such as:

* bytes uploaded/frame
* buffer wraps
* buffer stalls/waits
* mapped-buffer utilization
* fallback-path usage

4. Instancing for repeated geometry

Look for repeated UI geometry that can benefit from instanced rendering.

Examples:

* rectangles
* borders
* list rows
* repeated icons
* panel elements
* repeated simple widget primitives

Requirements:

* Do not introduce instancing merely for architectural elegance.
* Use it only where it reduces draw calls or CPU submission cost compared with the current batching system.
* Compare instancing against the existing batcher carefully because batching may already solve some of this problem.
* Prefer an architecture where batching and instancing complement each other.

Potential per-instance data:

* transform/position
* size
* UV rectangle
* color
* clipping/scissor-related information where practical
* texture/atlas index
* flags

Expose:

* instance count/frame
* instanced draw count
* non-instanced draw count
* average instances/draw

5. Render-state sorting

Improve the batching/render submission stage so compatible draw commands are grouped to minimize expensive state changes.

Consider sorting/grouping by:

* shader/program
* texture or atlas page
* blend mode
* primitive type
* framebuffer/render target
* other genuinely relevant GL state

Important:

* Preserve correct painter/order semantics.
* UI elements that require strict draw ordering must remain visually correct.
* Do not globally sort translucent UI in a way that changes composition.
* Use stable grouping or ordering barriers where necessary.

Track:

* shader changes/frame
* texture changes/frame
* blend-state changes/frame
* framebuffer switches/frame
* total GL state changes/frame

6. Reduce redundant OpenGL state calls

Audit the renderer for repeated calls such as:

* glUseProgram
* glBindTexture
* glBindVertexArray
* glBindBuffer
* glBlendFunc / glEnable / glDisable
* glScissor
* framebuffer binds
* uniform updates

Implement a lightweight GL state cache where appropriate.

Requirements:

* Skip calls when the requested state is already active.
* Keep the cache synchronized with GLDoze's renderer.
* If external/plugin rendering can modify raw OpenGL state, create explicit invalidation or state-restoration boundaries so the cache cannot become incorrect.

7. Uniform/update optimization

Inspect frequently updated uniforms.

Where appropriate:

* move per-frame/global data into UBOs
* avoid re-uploading unchanged uniform values
* batch common projection/viewport data
* consider SSBOs only where they provide a clear advantage

Do not over-engineer this if uniform overhead is currently negligible.

8. Frame-idle optimization

Because GLDoze is a desktop environment, optimize specifically for the case where very little is changing.

At a fixed refresh rate such as 75 FPS:

* avoid unnecessary CPU work
* avoid unnecessary geometry rebuilds
* avoid unnecessary texture updates
* avoid submitting unchanged content where possible
* allow the GPU to return to lower power states between frames

Do not break:

* animations
* timers
* cursor responsiveness
* window updates
* video/media
* plugins that request redraws

The goal is reduced GPU utilization and power consumption, not merely higher uncapped FPS.

9. Profiling and verification

Before making each major optimization, identify the current bottleneck and collect baseline metrics where possible.

Add or extend profiler counters for:

* frame CPU time
* GPU frame time
* draw calls
* batched draw calls
* triangles/vertices
* texture binds
* shader switches
* buffer uploads
* bytes uploaded
* dirty area percentage
* GL state changes
* instanced draws
* atlas usage
* time spent constructing render commands
* time spent submitting GL work

Where supported, use OpenGL timer queries for GPU timings rather than estimating them from CPU frame time.

Important:

* Do not optimize blindly.
* If an optimization provides negligible benefit or makes the renderer more complicated for no measurable gain, document that and do not force it in.
* Prefer measurable improvements over theoretical ones.

Architecture constraints:

* Preserve the existing public rendering ABI.
* Preserve plugin compatibility.
* Preserve existing window/widget behavior.
* Preserve the current scissor, batching, and occlusion systems.
* Keep optimization implementation modular and understandable.
* Do not spread low-level OpenGL details unnecessarily throughout UI/widget code.
* Prefer improvements inside the renderer/render-command infrastructure.

Implementation strategy:

Phase 1:

* Inspect the rendering architecture and profiler.
* Map the current frame/render pipeline.
* Identify likely stalls, excessive state transitions, uploads, and redraws.
* Produce a brief implementation plan based on the actual codebase.

Phase 2:

* Implement the highest-value low-risk improvements first:

  * redundant-state elimination
  * render-state grouping
  * dirty-region tracking
  * profiler instrumentation

Phase 3:

* Implement persistent mapped streaming buffers if appropriate.
* Benchmark against the existing buffer-update path.

Phase 4:

* Implement or improve texture atlas support.
* Integrate it into batching.

Phase 5:

* Add instanced rendering only for cases where measurements show a benefit.

Phase 6:

* Perform a final optimization/cleanup pass and compare results against the baseline.

Do not stop at designing this. Inspect the repository and implement the changes.

After implementation, report:

* files changed
* architectural changes made
* optimizations implemented
* anything deliberately not implemented and why
* measured before/after results where available
* draw-call/state-change reductions
* CPU/GPU frame-time changes
* any regressions or compatibility considerations

Build and test after meaningful stages rather than waiting until the very end.

Be conservative about correctness and aggressive about eliminating measurable rendering overhead.
