开发者

Is it safe to point to the middle of a valuetype in C#/CLR?

开发者 https://www.devze.com 2023-01-31 14:39 出处:网络
I have a Matrix4D that should be passed to glLoadMatrixf. To overcome p/invoke overhead (i.e. pinning, marshaling etc. each time), I\'m using pointers instead of usual arrays. So I have two issues.

I have a Matrix4D that should be passed to glLoadMatrixf. To overcome p/invoke overhead (i.e. pinning, marshaling etc. each time), I'm using pointers instead of usual arrays. So I have two issues.

  1. Matrix4D is based on a copypasted class. It's tested and probably optimized a bit -- didn't want to reinvent the wheel (also I suck at math). Anyway,开发者_JS百科 that class uses 16 fields instead of 1 fixed array (the class was written in the C# 1.0 era I guess). The layout is sequential, so that GetPointer method just gets a pointer to the very first field. THE QUESTION is: can there be some padding problems? I mean cases when, for example, the runtime extends floats to doubles so that indexing a pack of fields as an array would get garbage. Or does sequential layout prevent that by specs? Or should I adhere strictly to fixed arrays?

  2. The second issue is possible alterations by the optimizer. The matrix is a value type, on which float* GetPointer() is called. I'm afraid the optimizer may rearrange the code in such a way that GetPointer would point to some garbage.

For example:

GL32NativeMethods.glLoadMatrixf((mat1 * mat2).GetPointer());

Is it safe to do, or not? Currently I'm doing this to be sure (though I'm not sure at all):

Matrix4D tmp = mat1 * mat2;
GL32NativeMethods.glLoadMatrixf(tmp.GetPointer());

Are there other possible solutions to this problem? P.S. After the call to glLoadMatrixf, the pointer isn't needed.

UPD

My concern is that in between the calls to GetPointer() and glLoadMatrixf() the value may be discarded by the optimizer (as I suppose):

float* f = mat.GetPointer();

// Here the optimizer decides to discard mat variable because it isn't used anymore.

// Maybe it now fills the memory area of mat with other helper values (for P/Invoke, for example?)

GL32NativeMethods.glLoadMatrixf(f); // References discarded data.


Heh, I plumb forgot that native code is type-agnostic, i.e. it's actual memory alignment that matters. I'll try out this one:

public static extern void glLoadMatrixf(ref Matrix4D mat);
GL32NativeMethods.glLoadMatrixf(ref mat);

Native code will be tricked into thinking that mat is an array of floats, although it's actually a valuetype with the alignment of a float array.


I wrapped OpenGL methods in the following way:

    public static void UniformMatrix4(int location, Int32 count, bool transpose, float[] value) {
        unsafe {
            fixed (float* fp_value = value)
            {
                Delegates.pglUniformMatrix4fv(location, count, transpose, fp_value);
            }
        }
    }

    [System.Runtime.InteropServices.DllImport(Library, EntryPoint = "glUniformMatrix4fv", ExactSpelling = true)]
    internal extern static unsafe void glUniformMatrix4fv(int location, Int32 count, bool transpose, float* value);

Then, I can use a float[] for specifying matrix components. Of course there's a Matrix class which defines the array of floats and abstract math operations.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号