0

I have an openvr binding which has a minor problem since a while

Essentially, from time to time, whenever I free the memory of some geometric 3d model (basestation or controller) I get the Error:

"java.lang.Error: Invalid memory access"

This is the test I'm using so far, it loads and free x times a list of models present in the Steam installation folder:

for (i in 0..99)   models.forEach(::loadRenderModel)

fun loadRenderModel(renderModelName: String) {

    var error: EVRRenderModelError

    val rm = vrRenderModels!!

    val pModel = PointerByReference()
    while (true) {
        error = rm.loadRenderModel_Async(renderModelName, pModel)
        if (error != EVRRenderModelError.Loading) break
        Thread.sleep(1)
    }
    val model = RenderModel.ByReference(pModel.value)

    if (error != EVRRenderModelError.None) {
        System.err.println("Unable to load render model $renderModelName - ${error.getName()}")
        return // move on to the next tracked device
    }

    try {
        rm freeRenderModel model
    } catch (e: Error) {
        System.err.println(e)
    }
    println()
}

RenderModel struct in C++:

struct RenderModel_t
{
    const RenderModel_Vertex_t *rVertexData;    // Vertex data for the mesh
    uint32_t unVertexCount;                     // Number of vertices in the vertex data
    const uint16_t *rIndexData;                 // Indices into the vertex data for each triangle
    uint32_t unTriangleCount;                   // Number of triangles in the mesh. Index count is 3 * TriangleCount
    TextureID_t diffuseTextureId;               // Session unique texture identifier. Rendermodels which share the same texture will have the same id. <0 == texture not present
};

and in Kotlin:

open class RenderModel : Structure {

    /** Vertex data for the mesh    */
    @JvmField
    var rVertexData: RenderModel_Vertex.ByReference? = null
    /** Number of vertices in the vertex data   */
    @JvmField
    var vertexCount = 0
    /** Indices into the vertex data for each triangle  */
    @JvmField
    var rIndexData: ShortByReference? = null
    /** Number of triangles in the mesh. Index count is 3 * TriangleCount   */
    @JvmField
    var triangleCount = 0
    /** Session unique texture identifier. Rendermodels which share the same texture will have the same id. <0 == texture not present   */
    @JvmField
    var diffuseTextureId = INVALID_TEXTURE_ID

    val vertices
        get() = rVertexData?.pointer?.getByteArray(0, vertexCount * RenderModel_Vertex.SIZE)

    val indices
        get() = rIndexData?.pointer?.getByteArray(0, triangleCount * 3 * Short.BYTES)

    constructor()

    constructor(vertexData: RenderModel_Vertex.ByReference, vertexCount: Int, indexData: ShortByReference, triangleCount: Int,
                diffuseTextureId: Int) {
        this.rVertexData = vertexData
        this.vertexCount = vertexCount
        this.rIndexData = indexData
        this.triangleCount = triangleCount
        this.diffuseTextureId = diffuseTextureId
    }

    override fun getFieldOrder()= listOf("rVertexData", "vertexCount", "rIndexData",
            "triangleCount", "diffuseTextureId")

    constructor(peer: Pointer) : super(peer) {
        read()
    }

    class ByReference : RenderModel, Structure.ByReference {
        constructor() : super()
        constructor(peer: Pointer) : super(peer)
    }

    class ByValue : RenderModel(), Structure.ByValue
}

I tend to believe everything so far (regarding class definition) is correct since I do read valid values.

However I keep getting that error from time to time, I checked some pointer values and I didn't spot any weird value

What can it be?

elect
  • 6,765
  • 10
  • 53
  • 119
  • Is it the documented contract that you own the pointer to what `loadRenderModel_Async` provided? – Marko Topolnik Feb 22 '18 at 10:18
  • Sorry, but what do you mean exactly? [Here](https://github.com/ValveSoftware/openvr/blob/master/headers/openvr.h#L3304-L3313) and [here](https://github.com/ValveSoftware/openvr/wiki/IVRRenderModels::LoadRenderModel) some documentation – elect Feb 22 '18 at 10:21
  • I was wondering if that factory function was doing some caching, which would make it illegal for you as the client to release the memory. Apparently from the docs, the caller is responsible to free the pointer. – Marko Topolnik Feb 22 '18 at 10:28

1 Answers1

1

I found a bug in your code, but I can't confirm it is the reason of your failures. It definitely could produce them.

You say

val error = EVRRenderModelError.None

and then

if (error != EVRRenderModelError.None) {

which is a constantly false condition. Normally there's an IntelliJ inspection that warns you about these errors, but it could be disabled in your config.

You should use a var error instead and reassign it within the busy-wait loop of the async call.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Yeah, right, I modified it accordingly (it was some relict from some old code), however it doesnt look to be the cause – elect Feb 22 '18 at 10:37