Skip to content

[DirectX 12] Backend - #648

Merged
mikke89 merged 7 commits into
mikke89:masterfrom
wh1t3lord:master
Apr 2, 2026
Merged

[DirectX 12] Backend#648
mikke89 merged 7 commits into
mikke89:masterfrom
wh1t3lord:master

Conversation

@wh1t3lord

Copy link
Copy Markdown
Contributor

Introduction

So it is a new backend from me and it's DirectX 12 for Microsoft NT platforms (>=Windows10).

The library comes to a stage that it is needed to provide more user friendly interaction between end user and library, what relates to rendering backend is a simple and naive integration like in the popular library ImGui by Ocornut where user already has an integrated backend and they need to pass an initialization structure with all required parameters.

Well I will describe more detailed this chapter but for now I just leave this message in a such poor state, because for now it is a reminder for me to finish this work and move to Vulkan implementation.

Backend architecture

I set a straight aim to provide an efficient and optimized resource management and provide to user the low level settings of resource allocation. I mean that backend strives for being simple from user's side (in terms of how to set things up) and from another side it optimizes in all ways possible.

Buffer management aka geometry

About buffer management the library allocates one buffer and utilizes all its space the offset calculation is based on this offset allocator implementation by sebbbi (see sources, MIT license).

But if buffer is out of memory or offset allocator can't allocate the required space it will allocate a new buffer.

And rendering system tries to deallocate the buffer if it is not used. (in optimized way of course)

For now I tested with a really small sized buffers like less 1Kb and it was stable, of course it is not optimal settings due to high allocation of buffers and defragmentation of GPU's memory. By default I picked an optimal size that for most cases should be enough for using, but as I stated earlier user has a right to change that allocation size on initialization stage.

Texture management

DirectX 12 has two types of allocation of textures.

First one is to send texture to GPU as a single buffer, like if it is 4 Mbs then we send 4 Mbs as one single buffer. It is straight and simple and generally used among all modern GAPIs.

But there's a second variant for allocating textures aka placement PlacedResource (see link). That means you can allocate multiple textures into one buffer like you allocate one big buffer and suballocate space for textures thus it is like you "placed" those textures into one buffer. But that works only for not big sized textures that less some specific size, because in official tests it won't give any profit from performance, but still useful for rational resource management.

So based on texture size and its calculation the system tries to choose best way for uploading it.

As a conclusion I tried to make backend that utilizes all memory efficiently as much as possible and make all possible to fill all buffers and buffers for textures in most optimal way that user doesn't need even think about it at all.

Warning

Since we formally force people to use our backend then I don't see any motivation to help to people who make own backends based on our implementations and there's a vital reason for this, because it is better to have "one" (not in directly meaning) backend that be tested on many devices across different OSes than having some custom backends that can't be well tested at all. It is important warning for all users who have tendency to make own wheel ignoring obvious sane way of living.

I need to say that I tried to keep things without breaking changes at all, like if you want to initialize RmlUI as you did before you just don't pass an init structure and from function calling it is just a default argument that you don't specify thus nothing is changed/broken.

But we will (at least me) accept all incoming that relate to backend and it's working state on different graphics cards and OSes for @mikke89 I suggest to create template issue that has the following form (just as an idea):

If you have trouble with rendering backend

Specify GAPI

Blah 12

Specify graphics card's driver

Blah 12.451.16 oct 2023

Specify graphics card

Blah RTX 24000

Specify OS

Blah 13

Specify version and commit of RmlIUI

6.0 d23a3da

I guess after finishing "modern" backends we will boost for some time the popularity of library but at the same time amount of running tests and examples would be high since everyone can easily integrate the library... :D

For now I am making support for multisampling feature and I hope I will finish this work till August.

@mikke89 mikke89 added the backends Platforms and renderers label Aug 11, 2024
@mikke89

mikke89 commented Aug 11, 2024

Copy link
Copy Markdown
Owner

Thanks a lot for working on this, a DirectX 12 backend will be a very welcome addition! Let me know once you feel it is ready for review.

I quite like the initiative for introducing such a "renderer initialization" type that provides the user's own parameters. Although, I'll have to think a bit more about this, and how it fits into the library and how it integrates. I think it's important to keep it so that we don't take control over the main loop and event system, to ensure that the library plugs in to their existing infrastructure. Which is why we currently say that users should copy the backend itself into their own code (as opposed to the renderer and platform parts of the backend). But at the same time, we want to make it easier to get started for users that perhaps only want to provide their renderer details, but otherwise use the backend as it is. This generally looks like a nice opt-in solution that could be helpful in many use cases, but I'll need to take some more rounds and think about it.

Regarding issue templates. I actually quite like the informal nature of giving users a blank slate to describe their issues. I think that has some value as a community. Of course, I understand that with growing number of issues, some system like this could be helpful to speed things up, but I don't believe this is an issue for us at this point. I generally find that users are good at describing their issues. Regardless of templates, there will always be some times where more information is necessary. And that is perfectly fine in my view, there is also some value to this interaction as well. So I would prefer to keep this as it is.

@Paril

Paril commented Aug 12, 2024

Copy link
Copy Markdown
Contributor

Regarding issue templates. I actually quite like the informal nature of giving users a blank slate to describe their issues.

Just wanted to chime in on this one and say I agree; overly-complicated forms and templates have dissuaded me from making issues on other projects (same for something like stalebot, which I hate even more). I understand why some people use them but I find most people are pretty good with issue-posting when you don't give them any instructions at all.

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 Hi and I have some good news! 😃

I know it is kinda late and I was hell busy in that matter of time when I wrote that I am gonna finish that thing 😞 (I swear) but what happened that happened 😁

image

image

image

DirectX-12 probably is closing to be finished! Also I would like to add that I marked all methods for CPU and GPU profilers (GPU only those methods/functions where any calling from API is issued and it is helpful for debugging purposes for marking functions callings from API)

Anyway, I need to warn that you should think about passing invalid viewport/scissors and how it handle from frontend side because in DirectX-12 the scissor test is always enabled and in such case we get error like nothing happens much on Debug you will receive error (like debugbreak every time) or if you suppress (what I did now) a warning and it is kinda annoying :D

I did experiment and treated a such situation where invalid scissor and vp is passed like not suppressing from API side but manually and in such case half of frames are not rendered at all like you get empty clear window's background without those buttons and other subwindows regions so it didn't work out as expected.

The warnings are like these:

D3D12 WARNING: ID3D12CommandList::DrawIndexedInstanced: Viewport: 0 is non-empty while the corresponding scissor rectangle is empty. Nothing will be written to the render target when this viewport is selected. In D3D12, scissor testing is always enabled. [ EXECUTION WARNING #695: DRAW_EMPTY_SCISSOR_RECTANGLE]

D3D12 WARNING: ID3D12CommandList::ClearRenderTargetView: Empty rect (left >= right or top >= bottom) means it not will clear anything.pRects[0] = { left:108, top:960, right:212, bottom:960 } [ EXECUTION WARNING #448: DEVICE_CLEARVIEW_EMPTYRECT]

Currently I need to finish some little things like checking Release build configuration (maybe I forgot something but geometry is kinda sus rendering but on Debug is all fine even validation layers didn't say anything illegal, no errors) and provide implementation of integration sample and to show minimal sample how RmlRenderInitInfo works (it is just matter of some hours, probably tomorrow I will write back here), and implement SDL, GLFW backend for DX12 it is small tasks too.

Because now we get everything works like all existed samples + effects sample but on your side I would be glad if you check visual tests and report something unusual or just some mistakes (probably when I will write that it is ready to be merged). I won't touch Readme and you can fill all needed information like updating backend table :)

I would like to hear any critique for default arguments that can be changed for/from user and they exist here

https://github.com/mikke89/RmlUi/blob/cbb4ea1015cc633e42fbe9906cb611da061cc498/Backends/RmlUi_Include_DirectX_12.h

And discuss it like what you like what you don't like and etc, because my aim was to handle all situations like why I choose preprocessors because some users can build RmlUI manually and they would like to change constants but themselves without CMake generations steps (configuration) from another hand there's a thing for CMake users too they can just pass their overrides and just use what they want to and if user doesn't need to change anything they will be used (and just used) as defaults in case if user didn't specify in RmlRenderInitInfo (I didn't make CMake side so it is better for someone to finish that feature, so it means that defaults will be generated and maybe as whole file through CMake)

About RmlRenderInitInfo it serves for two purposes

  1. Just pass all related things for using backend out-of-box, if it is detailed GAPI like DX12,VK they pass devices swapchains and other things
  2. If user specifies that it needs to override internal resource allocation policies, how much memory we reserve, how much of other things then that information will be use at initialization stage. A such feature is really useful among different teams from big projects or small they just pass their required limits for shipping and it works.

Also something worries me about constant buffers (uniform buffers) I mean they're a lot of them and would be better to think about possible optimization how to pass that data to shaders in reduced manner, maybe it is okay, but if there's something that might be improved in terms of their amount it would be perfect (I didn't think personally about how to reduce them yet)

I would like to hear other people and who used our backends and to hear their wishes/needs/discontent

@mikke89

mikke89 commented Jun 23, 2025

Copy link
Copy Markdown
Owner

Hey, that's great news! Looks very promising, good job!

I'll have to get back to you with more testing and after taking a closer look.

Regarding the configuration parameters. I think it's good to have anything that should be tunable easily accessible like that, so I'm all for that. I would perhaps simplify it a bit, and just do #ifndef RMLUI_... #define RMLUI_... #endif, instead of the separate override macro.

Nice work! :)

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 hi mikke I implemented the integration sample and I really recommend for you to implement the GL3 integration samples following my design and understanding my ideas and way of implementing things, but I tried to achieve two things:

  1. Make really small steps for integrating for user and thus easy callings, simplifying and being nice for consumer
  2. Make things without any breaking changes related to current RmlUi samples and generally RmlUi functions of namespace Backend

But I just spend not so much time for making things beauty (in terms of code) and for that I recommend that thing for you :))

At least just to know that you would make things as you want to see because I can't know how's better to handle/write things from your side and not making any interferences you can finalize my idea about integration thing so better for you to refactor I just made things working.

Then I really want to upgrade our Vulkan and make effects sample working and we will have new way of using our backends for user environment and they don't need to copy/paste files and just directly use our code of RmlUi library. 😄 🎊 💯

Yeah I will finish postprocess integration sample, but for now swapchain works it is just example of load document sample and I think I need to test on effects sample that will be renderered onto swapchain image.

So my idea is to provide for user two integration examples:

  1. First example when user just wants to pass swapchain images directly where graphics information be rendered into swapchain
  2. Second example when user just wants to render things as postprocess so he just passes single render target (framebuffer) renders rmlui interface onto that image and then using quad geometry rendering that postprocess image as texture for that quad and displaying on swapchain
  3. This example just demonstrates same as postprocess but user wants to us make own command list and execute things so when Backend::EndFrame() is called on user's side he will get already rendered postprocess image without waiting and pushing commands for queue execution, this example is not added yet as well as a such feature as making isolated command list and command list execution is not finalized yet too

So yeah, the main thing of integration sample it must be implemented from scratch demonstrating user engine's environment and show all things in one file and we just show using commentaries the needed steps for integration. I really want to see some users that have multithreaded renderers in their engines and thus they would like to render UI in some of separated thread and they have to report like there's no samples that will demonstrate a such integration, but still it must be a generalized solution, we will see I guess.

The really last thing what I need to fix and resolve for Dx12 it is CompositeLayers function where Blur and DropShadow render somehow the image result is flickering and idk why I forced to use Flush method (you can see in

) and for some matter of time it is okay (performance doesn't degenerate) but still it is not right in terms of development and rendering, I will investigate and fix it for now just don't want to focus on that yet.

I tested my backend on three videocards they are all Nvidia videocards so

GTX 1060 Ti 6 GB (PC), GTX 1660 Ti 6 GB (PC), RTX 3060 laptop 6 GB (notebook)

No one of them reported any problems, but I suggest to your known testers (and you personally) to use their videocards and run our samples on debug make with RMLUI_DX_DEBUG preprocessor enabled in order to get and receive any missed barrier (because when I thought that I finished development and when my 3060 didn't show any troubles the GTX 1660 showed me the one missed barrier so it is quite reasonable to test on other videocards that users have), BUT it is really important to run without Flush calling where I show in CompositeLayers.

Also funny fact the GTX 1060 renders well with or without Flush calling in CompositeLayers so I really hope it is possible to debug that thing and to understand where the problem on modern GPUs, but just FYI.

Currently integration samples will add only on DX12 (using standard procedure cmake -B Build_Win32_DX12 -S . --preset samples -DRMLUI_BACKEND=Win32_DX12 -DCMAKE_TOOLCHAIN_FILE="//scripts/buildsystems/vcpkg.cmake"), but when you make GL3 you can add GL3 in cmake file of these samples by path Samples\basic\integration and Samples\basic\integration_2 (maybe I should rename as integration_swapchain and integration_2 as integration_postprocess but I thought it is too long names but whatever)

And yes, since we have a situation where backend and shell samples can run under different window management libraries or native that means we have to provide all integration samples for each of window management libraries or native implementation, for now we have only win32 I added temporary the others sdl and glfw for integration samples but I didn't complete them.

And yeah I know my explanation is kinda chaotic but it was needed to make RmlUi_Backend.cpp file where "generalized" functions will be called for user integration purposes (you will when you will try to implement on my pull GL3 samples).

The main question about design is where to store implementation functions for each backend where user requests in Backend::Initialize and other related functions that have similar design approach as Backend::Initialize version for integration (see rmlui_sample_integration_as_swapchain on dx12) because for now in RmlUi_Backend.h I made namespace for each backend and their functions and maybe we need to isolate from public space and add prefix ___ like I did for renderer_type variable, for now only dx12 implemented but storing in native files like Win32_DX12.cpp it is idk so better for you to think about where to store them maybe it is okay since we stored in RmlRenderInitInfo information about window handle and that window handle will be proceed in respected ProcessEvents based on window management library or native implementation again it is still better for you to think about how to make things nicer I just wrote dumb variables but obviously we have to have some internal structure and better accessing and all that stuff, so see variables __renderer and p_integration_renderer).

Also we need to think about FileSystem and how to pass that thing for user, maybe we can use default ShellFileInterface but specify root from init info or just force user to pass own file interface (but I guess it is better that user expects that it resolves by itself like just hidden in Backend::Initialize function and maybe first approach is better where user just passes root maybe we can determine root if it wasn't passed by ourselves expecting just root as folder where application is executed or maybe to force user to pass root string otherwise if it wasn't passed we just say like failed to initialized backend)

if (!p_integration_file_interface)

Still I would like to hear any feedback from your side, thanks.

2025-07-05.18-08-38.mp4

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 hi, any news? 🙃

@mikke89

mikke89 commented Jul 18, 2025

Copy link
Copy Markdown
Owner

Hey, and sorry for the slow response, it's been a bit too busy for me lately. I will have some more time soon to delve into this, and get back to you. :)

@mikke89

mikke89 commented Jul 23, 2025

Copy link
Copy Markdown
Owner

Hello again!

First of all I want to say it's a really nice effort! It's a great feat to have implemented all the features in a new render interface. I have been testing it a bit now, and started looking through it. The effects sample seems to be working well for me. I do find some issues in the visual tests.

It is a lot to chew over all at once. Especially with both the new render interface and the changes you're making with the backend initialization and integration. I would say these are really two very different set of changes, both of which are really large. And it's impossible to discuss all of that at once. The backend initialization in particular requires some more discussion and design iterations I think. Thus, I suggest that we split this pull request in two, or possibly more, and discuss each change separately. I'll keep the rest of this post about the DX12 renderer, assuming we take the other parts in a separate PR.

I'm seeing some issues in the visual tests, I'll just list my findings here, in no particular order:

  1. After looping through all the tests, I usually (although not always) hit a crash. It fails an assertion with "can't allocate virtual alloc!". For reference, I'm using a GTX 1070 with 8 GB RAM.
  2. It would be useful to implement the screenshot feature (see RendererExtensions.cpp), as that would make it easier to compare the visual tests with other renderers.
  3. The alpha blending tests are not entirely correct (renderer_alpha_blending_02/03). The color circles are missing from the black background, and one of them in the white background.
  4. I'm seeing some flashing on document load on the first element in filter_backdrop_filter_box_shadow.rml, and the result doesn't seem to be entirely correct.
  5. The rendering of filter_blur_area and filter_blur_orb it not correct. And some of circular clipping from these filters seems to "stick around" when switching to other tests.
  6. Also, I could only get the Win32_DX12 backend to compile, the other ones had some build errors. And there are a lot of warnings too.

I think that's what I found so far. Otherwise, a lot of things are working really well, and the gradients and such looks correct from that I could tell, that's really nice.

@wh1t3lord

wh1t3lord commented Aug 13, 2025

Copy link
Copy Markdown
Contributor Author

Run effects sample and didn't get any errors of rendering execution on RTX 5070 Ti 16 Gb, no validation error report at all and Flush calling doesn't affect execution at all that means that current barriers are all valid but somehow it is broken on 3060 and 1660 and output image doesn't look stable at all (Interesting to note that capturing video or capturing by debug rendering profilers like Nsight or RenderDoc makes image stable and it is hard to report about it problem only recording outside of OS itself e.g. phone/camera). That's actually sad, hope it might be fixed in future driver updates for these videocards otherwise I will try again to investigate where the barrier was missed :/

So right now I tested using these videocards:

Videocard Validation Status (Full Debug) Stable image without Flush in CompositeLayers Method?
GTX 1060 Ti (6 Gb)
GTX 1660 Ti (6 Gb) 🔴
RTX 3060 laptop (6 Gb) 🔴
RTX 5070 Ti (16 Gb)

Yeah I don't have AMD videocards so if any of you have it I would like to hear some feedback and to understand is there any validation errors, because AMD has some strict execution policies and some of AMD videocards might report about missed barrier-(s)... But 4 videocards and from different timeline differences and they all didn't report about any troubles I guess we're good for now (?)

That's actually sad thing, because 1060 was released in 2016 but 5070 in 2025 so these cards work fine due to their drivers but 1660 is close to 1060 and has stable image problem as well as modern laptop 3060. But what about 1660 and 3060 it is really hard to say. Honestly I expected any validation errors but got none. I will try to iterate and find the 'leaked' barrier but my sanity supposes that I did all good.

image

@wh1t3lord

Copy link
Copy Markdown
Contributor Author
image

I am lucky and captured by windows snipping tool what I mean about 'stable image problem'. In this example 3060 was used. Expected to see blur but there's no blur, but on Debug it was okay...

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 hi I pushed the fixes related to your last report and verify everything that works good please (and I didn't bring new bugs lol), for now I need to finish postprocess integration sample and that annoying blur bug that exists in effects sample.

Personally I hope when I port Vulkan it will show me exact problem where the sync primitive is missed but for now it is only iterational approach to understand what works not good due to missed barrier. It is def compositelayers place but debug validation doesn't say anything bad on all video cards 🫤🫤🫤

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 just FYI, I refactored upload policy for textures and improved it so we create staging buffer that uses two fields check if user wants to upload texture that bigger than initial size of staging buffer than it has dynamic nature as it was before (uses temp buffer but allocates for requested size), but now we allocated that buffer once and until we didn't face a such big texture we just re-use existed buffer without constant allocation/deallocation that can leads to bad things as degraded performance with time and possible (in theory) memory fragmentation.

Same thing I did for Vulkan.

@mikke89

mikke89 commented Oct 20, 2025

Copy link
Copy Markdown
Owner

Yeah, I think that sounds very reasonable, to keep one buffer like a sort of scratch buffer.

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 revisited again the trouble with effects sample where it was guessed that barrier was missed but now when Windows 11 dropped update related to DX12 SDK the bug was gone (aka stable image problem). Probably it was the SDK's or Driver's bug because my investigations showed that on our side it was clear and we didn't get any validation error report related to barriers usage so on trouble videocards the bug is gone on debug/release configurations. So in any user report it goes to vendors report not to us.

So the last thing I need to finish and I will do that very soon it is postprocess sample and you can start to merge my work (also I need to fix all warnings :D).

I fixed the new API validation error it is really minor but annoying.

NVIDIA 3060 laptop RTX (Release)

nv3060rtxlaptop.mp4

@mikke89

mikke89 commented Oct 27, 2025

Copy link
Copy Markdown
Owner

Very nice! Thanks for the update, looks really good!

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 I finished my integration samples for win32 but for other input platforms like glfw3, sdl2, sdl3 (if they're not finished and probably they're not finished because it is separated files) it is just copy and paste code from native win32 samples and just change code (replace win32 loop messages and provide functions from these libraries respectively), anyway

So you can start to merge my work, but keep in mind that:

  1. You should verify and validate my vision about integration architecture, it might seem raw at first glance and maybe it requires some refactoring (somewhere to rename, somewhere to make consistent by writting and etc), but it is just improtant that you understand my idea and you agree with my design (or at least knowing my idea and my approach you could formulate yours in case if my variant is not sufficient for making extendable and easy-maintanable thing but I guess it is okay though :D), still at least spend some time and think about others backends/new backends that could be provided from other people and does it fit easily/comfortably and etc

  2. About integration itself, I tried to not reduce freedom of users and what they would like to do, but I made two versions of how possibly ever user can use renderer it is just directly use swapchain images and render to them or just make postprocess approach, it depends on use-case, it depends on users condition, business environment what they can do, what legacy they have and etc, but from my understanding it could be enough for them, so only question is about like it is okay for them to use that init struct or not, I tried to ask user a minimum info from their side like what to fill in struct but maybe we can wait some time and people would like to give some feedback (i just don't know), ofc there could some elaborate and reason about why not to provide just output image for user but... it would be reasonable if we are closed source library, but since we provide source for everything we could at some point expect that users would like to edit code of existed renderer and we just don't know how they would like to operate with library so full freedom to them as I would say. From my point of view just making one variant and forcing all people using it I am not sure that it is okay so I did both possible variants

What I didn't yet implement it is .is_execute_when_end_frame_issued when true and .p_command_list fields are true and nullptr (or it might not nullptr it depends, but still it is main thing is when .is_execute_when_end_frame_issued==true) respectively, so according to this it fits for multithreaded variant where user just push whole UI to different thread, we have probably dedicated queue from GAPI and we push commands and it executes separately to main render but I don't know maybe it is too much rn I just want to see at least half of my work will be merged and then we can talk further otherwise we could stuck for a long time with such timings...

  1. Probably there should be a thing with what we can easily change pages for demonstration in integration samples but again it is up to you (or me, or any other volunteers). But The beginning has been made and it is great :)

So I hope you doing well, happy holidays

Best regards

@mikke89

mikke89 commented Dec 29, 2025

Copy link
Copy Markdown
Owner

That's great! Glad to hear that, and thanks for the continued work on this one.

I'm a bit backlogged right now, but I'll come around to this eventually. I might make some changes or additions (like the other backends) as I see fit, and then I'll likely just merge it. It's been some time in progress, and I agree that it's better to have something merged in sooner, rather then discussing minor details, and then everyone can help improve it over time.

Cheers!

@mikke89

mikke89 commented Feb 1, 2026

Copy link
Copy Markdown
Owner

Hey, I've been working to get this one ready to merge lately. First of all, nice job getting so many of the effects working.

I have pushed my changes now. To summarize quickly:

  • I split out all the integration stuff, to focus only on the DX12 backend here. It's just way too much to do all of that at once in a single PR. We need several more iterations for the integration, so we'll have to do that in a follow-up instead.
  • Cleaned up some things, fixed up all the TODOs I could find.
  • Fixed up the other backends (SDL_DX12 and GLFW_DX12).
  • Adding some additional licensing notices.

I found two issues that I consider merge-blocking:

  1. There seems to be a resource leak. To reproduce:
    1. Build with RMLUI_DX_DEBUG enabled.
    2. Build and run rmlui_sample_effects.
    3. Click the green question mark to open the debug logs.
    4. Close the application. This triggers an assertion on shutdown.

Here is the full assertion and backtrace:

Assertion failed!

Program: ...\BuildClion\dev-all-debug\rmlui_sample_effects.exe
File: C:\Projects\RmlUi\Backends\RmlUi_Di.../D3D12Me...loc.cpp
Line: 10241

Expression: m_Pimpl->m_Metadata->IsEmpty() && "Some allocations were not freed before destruction of this virtual block!"

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts

(Press Retry to debug the application - JIT must be enabled)(lldb) bt
* thread #1, name = 'Main Thread', stop reason = Exception 0x80000003 encountered at address 0x7ffd26fcf575
  * frame #0: 0x00007ffd26fcf575 ucrtbased.dll
    frame #1: 0x00007ffd26fcf393 ucrtbased.dll
    frame #2: 0x00007ffd26fd1c7f ucrtbased.dll
    frame #3: 0x00007ff65be8e926 rmlui_sample_effects.exe`D3D12MA::VirtualBlock::~VirtualBlock(this=0x00000240d5d7ce40 {m_Pimpl=0x00000240d858c340 {m_AllocationCallbacks={pAllocate=0x00007ff65beb54c0 {rmlui_sample_effects.exe!D3D12MA::DefaultAllocate(unsigned long long,unsigned long long,void *)}, pFree=0x00007ff65beb54f0 {rmlui_sample_effects.exe!D3D12MA::DefaultFree(void *,void *)}, ...}, ...}}) at D3D12MemAlloc.cpp:10241
    frame #4: 0x00007ff65bef1b28 rmlui_sample_effects.exe`D3D12MA::VirtualBlock::`scalar deleting destructor'(this=0x00000240d5d7ce40 {m_Pimpl=0x00000240d858c340 {m_AllocationCallbacks={pAllocate=0x00007ff65beb54c0 {rmlui_sample_effects.exe!D3D12MA::DefaultAllocate(unsigned long long,unsigned long long,void *)}, pFree=0x00007ff65beb54f0 {rmlui_sample_effects.exe!D3D12MA::DefaultFree(void *,void *)}, ...}, ...}}) + 24
    frame #5: 0x00007ff65beddc59 rmlui_sample_effects.exe`D3D12MA::D3D12MA_DELETE<D3D12MA::VirtualBlock>(allocs={pAllocate=0x00007ff65beb54c0 {rmlui_sample_effects.exe!D3D12MA::DefaultAllocate(unsigned long long,unsigned long long,void *)}, pFree=0x00007ff65beb54f0 {rmlui_sample_effects.exe!D3D12MA::DefaultFree(void *,void *)}, pPrivateData=0x0000000000000000}, memory=0x00000240d5d7ce40 {m_Pimpl=0x00000240d858c340 {m_AllocationCallbacks={pAllocate=0x00007ff65beb54c0 {rmlui_sample_effects.exe!D3D12MA::DefaultAllocate(unsigned long long,unsigned long long,void *)}, pFree=0x00007ff65beb54f0 {rmlui_sample_effects.exe!D3D12MA::DefaultFree(void *,void *)}, ...}, ...}}) at D3D12MemAlloc.cpp:214
    frame #6: 0x00007ff65be8e74b rmlui_sample_effects.exe`D3D12MA::VirtualBlock::ReleaseThis(this=0x00000240d5d7ce40 {m_Pimpl=0x00000240d858c340 {m_AllocationCallbacks={pAllocate=0x00007ff65beb54c0 {rmlui_sample_effects.exe!D3D12MA::DefaultAllocate(unsigned long long,unsigned long long,void *)}, pFree=0x00007ff65beb54f0 {rmlui_sample_effects.exe!D3D12MA::DefaultFree(void *,void *)}, ...}, ...}}) at D3D12MemAlloc.cpp:10231
    frame #7: 0x00007ff65be8c546 rmlui_sample_effects.exe`D3D12MA::IUnknownImpl::Release(this=0x00000240d5d7ce40 {m_Pimpl=0x00000240d858c340 {m_AllocationCallbacks={pAllocate=0x00007ff65beb54c0 {rmlui_sample_effects.exe!D3D12MA::DefaultAllocate(unsigned long long,unsigned long long,void *)}, pFree=0x00007ff65beb54f0 {rmlui_sample_effects.exe!D3D12MA::DefaultFree(void *,void *)}, ...}, ...}}) at D3D12MemAlloc.cpp:9591
    frame #8: 0x00007ff65be8ffbc rmlui_sample_effects.exe`RenderInterface_DX12::BufferMemoryManager::Shutdown(this=0x000002408bf4dc00 {m_size_for_allocation_in_bytes=2097152, m_size_alignment_in_bytes=256, m_p_device=0x00000240d5bee258 {}, ...}) at RmlUi_Renderer_DX12.cpp:7968
    frame #9: 0x00007ff65be99181 rmlui_sample_effects.exe`RenderInterface_DX12::~RenderInterface_DX12(this=0x000002408bf4d870 {m_is_use_tearing=true, m_is_scissor_was_set=false, m_is_stencil_enabled=false, ...}) at RmlUi_Renderer_DX12.cpp:963
    frame #10: 0x00007ff65bef1a88 rmlui_sample_effects.exe`RenderInterface_DX12::`scalar deleting destructor'(this=0x000002408bf4d870 {m_is_use_tearing=true, m_is_scissor_was_set=false, m_is_stencil_enabled=false, ...}) + 24
    frame #11: 0x00007ff65be862a5 rmlui_sample_effects.exe`std::default_delete<RenderInterface_DX12>::operator(this=0x000002408bf24598 default_delete, _Ptr=0x000002408bf4d870 {m_is_use_tearing=true, m_is_scissor_was_set=false, m_is_stencil_enabled=false, ...})(RenderInterface_DX12 *) at memory:3338
    frame #12: 0x00007ff65be86da8 rmlui_sample_effects.exe`std::unique_ptr<RenderInterface_DX12,std::default_delete<RenderInterface_DX12> >::reset(this=0x000002408bf24598 empty, _Ptr=0x0000000000000000 {m_is_use_tearing=???, m_is_scissor_was_set=???, m_is_stencil_enabled=???, ...}) at memory:3500
    frame #13: 0x00007ff65be83507 rmlui_sample_effects.exe`Backend::Shutdown() at RmlUi_Backend_Win32_DX12.cpp:158
    frame #14: 0x00007ff65be78db4 rmlui_sample_effects.exe`WinMain(__formal=0x00007ff65be40000 {unused=9460301}) at main.cpp:126
    frame #15: 0x00007ff65c2c7e82 rmlui_sample_effects.exe`invoke_main() at exe_common.inl:102
    frame #16: 0x00007ff65c2c7d32 rmlui_sample_effects.exe`__scrt_common_main_seh() at exe_common.inl:288
    frame #17: 0x00007ff65c2c7bee rmlui_sample_effects.exe`__scrt_common_main() at exe_common.inl:330
    frame #18: 0x00007ff65c2c7f1e rmlui_sample_effects.exe`WinMainCRTStartup(__formal=0x0000004f76d02000) at exe_winmain.cpp:16
    frame #19: 0x00007ffe10047374 kernel32.dll
    frame #20: 0x00007ffe10afcc91 ntdll.dll
  1. It seems running without MSAA does not work. Try changing RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT to 1 and run any sample (I currently added an assertion, but we should instead fix this).

Could you take a look at these two issues?

@wh1t3lord

Copy link
Copy Markdown
Contributor Author

@mikke89 hi thanks for testing I will check

@wh1t3lord

wh1t3lord commented Mar 23, 2026

Copy link
Copy Markdown
Contributor Author

@mikke89 I fixed the issues 😊

p.s. sorry for a long pause 😅 😅

@mikke89

mikke89 commented Mar 23, 2026

Copy link
Copy Markdown
Owner

That's really awesome, thanks! Good work :) I'll take one final glance over it and then expect to merge it soon.

@mikke89
mikke89 merged commit 704d27f into mikke89:master Apr 2, 2026
36 checks passed
@mikke89

mikke89 commented Apr 2, 2026

Copy link
Copy Markdown
Owner

Great stuff, it seems to be working well in my testing. I know this was a lot of effort, so thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backends Platforms and renderers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants