CNA-BUG-212: cna_graphics_resource_get_graphics_device returns CNA_RESULT_INVALID_HANDLE for every resource created on a caller-created GraphicsDevice
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
A resource made on a device from cna_graphics_device_create carries that device's handle as its owner token, and the route passes it to the game-only BorrowGameGraphicsDevice, so asking such a valid resource for its device always fails.
- Identifier
CNA-BUG-212- Category
- Bug
- Subsystem
- C API & bindings
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- cna_graphics_resource_get_graphics_device(CNA_Handle resource, CNA_Handle* out_graphics_device) (CNA/C/graphics_resource.h) for resources created on a cna_graphics_device_create device
Expected behaviour
graphics_device.h says a caller-created device's handle “is accepted everywhere a borrowed device handle is” and that “resources remember which device made them”; graphics_resource.h promises success with CNA_INVALID_HANDLE for a standalone resource and the owning device's handle for a device-owned one. A valid resource on a live caller-created device should therefore yield that device's handle, or a documented refusal such as CNA_RESULT_NOT_SUPPORTED, never a claim that a handle is invalid.
Actual behaviour at TARGET
cna_graphics_device_create builds the device's view as BorrowedGraphicsDevice{device, own handle}, so every resource created on it stores the device handle in its parentGame owner token (for example IndexBufferResource, CreateOwnedTexture2D). cna_graphics_resource_get_graphics_device sees a non-null device pointer and a non-invalid owner and calls BorrowGameGraphicsDevice(parentGame, ...), which calls GetGame; HandleRegistry::Get finds a slot of kind OwnedGraphicsDevice where it expects Game and answers CNA_RESULT_INVALID_HANDLE, reported as “The CNA game handle is invalid for this call.” The route thus fails for every such resource, while the device is alive and after it is destroyed alike.
Source locations
modules/c-api/src/CnaCApiGraphicsResource.cpp— cna_graphics_resource_get_graphics_device; ResolveGraphicsResource copies parentGamemodules/c-api/src/CnaCApiRuntime.cpp— BorrowGameGraphicsDevice calls GetGame; GetGamemodules/c-api/src/CnaCApiDisplay.cpp— cna_graphics_device_create makes the owner token the device's own handlemodules/c-api/src/CnaCApiDetail.hpp— HandleRegistry::Get returns CNA_RESULT_INVALID_HANDLE on a kind mismatchmodules/c-api/include/CNA/C/graphics_resource.h— Doxygen of cna_graphics_resource_get_graphics_devicemodules/c-api/include/CNA/C/graphics_device.h— Doxygen of cna_graphics_device_createmodules/c-api/src/CnaCApiRuntimeDetail.hpp— BorrowedGraphicsDevice owner-token comment
Evidence
Checked by reading CnaCApiGraphicsResource.cpp, CnaCApiRuntime.cpp, CnaCApiDisplay.cpp and CnaCApiDetail.hpp at 009d40f5; the owner token was traced for index buffers and 2D textures. Not executed (the C library was not built). graphics_resource.h's wording predates caller-created devices and does not name this case, so the exact intended answer (the device handle or a documented refusal) is an owner decision; returning CNA_RESULT_INVALID_HANDLE for a valid resource is the defect.
Independently observed as a separate finding (merged): A resource made on a device from cna_graphics_device_create carries that device's handle as its owner token, and the route passes the token to the game-only BorrowGameGraphicsDevice, so asking a valid resource for its device fails.
Focused reproduction
Illustrative only, not compiled:
CNA_Handle device = CNA_INVALID_HANDLE, texture = CNA_INVALID_HANDLE, owner = CNA_INVALID_HANDLE;
cna_graphics_device_create(0U, CNA_GRAPHICS_PROFILE_REACH, ¶meters, &device);
cna_texture2d_create(device, &texture_info, &texture);
CNA_Result r = cna_graphics_resource_get_graphics_device(texture, &owner);
/* by reading: r == CNA_RESULT_INVALID_HANDLE, owner == CNA_INVALID_HANDLE */
Current tests
GraphicsResourceSmoke.c calls the route for standalone resources, wrong kinds and game-device resources inside callbacks; OwnedGraphicsDeviceSmoke.c never calls it. The C tests are not run in CI.
Regression test
In OwnedGraphicsDeviceSmoke.c: create a texture on a caller-created device and assert that cna_graphics_resource_get_graphics_device succeeds with that device's handle (or returns the refusal the header is amended to document).
Blast radius
C and binding callers that ask a resource for its device when the resource was made on a caller-created device (the cross-device scenario that route was added for); creating, using and destroying such resources is unaffected, and game-device resources answer as documented.
Workaround
Keep the device handle that created each resource instead of asking the resource for it.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- C API: the model
- Known issues
- Bug index