Я пишу C ++ DLL для использования в приложении C #.
DLL проверит общий объем памяти GPU и использование памяти GPU.
Сейчас я создал три метода. Первый действительно инициализирует GLew и другие вещи OpeGl. Второй будет читать общую память графического процессора. И последний будет читать использование графического процессора.
Методы inialize и total memory работают, но с последним я получаю некоторые проблемы. Когда я вызываю метод, он останавливается, и когда я отлаживаю его, я могу установить точку останова на идентификаторах delete []; линия без проблем. Но он не возвращает ничего в строке возврата (он туда не попадает). Когда я удаляю строку delte [] ids, я получаю сообщение об ошибке:
‘Ошибка проверки времени выполнения # 2 — стек вокруг переменной’ nCurAvailMemoryInKB ‘был поврежден.’ Неужели я что-то неправильно прочитал об использовании памяти графического процессора?
__declspec(dllexport) float getAvailableMemory()
{
int available = -1;
if (wglGetGPUIDsAMD && wglGetGPUInfoAMD)
{
UINT n = wglGetGPUIDsAMD(0, 0);
UINT * ids = new UINT[n];
wglGetGPUIDsAMD(n, ids);
GLint nCurAvailMemoryInKB = 0;
glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI,
&nCurAvailMemoryInKB);
available = nCurAvailMemoryInKB;
delete[] ids;
}
return available;
}
Я создал тестовый вызывающий для Dll в C #:
Программа класса {
[DllImport("AmdLib.dll")]
public static extern bool init();
[DllImport("AmdLib.dll")]
public static extern int getTotalMemory();
[DllImport("AmdLib.dll")]
public static extern float getAvailableMemory();
static void Main(string[] args) {
init();
Console.WriteLine("Total");
Console.WriteLine(getTotalMemory());
Console.WriteLine("Available");
Console.WriteLine(getAvailableMemory());
}
}
И полный исходный код C ++ DLL выглядит так:
#include <stdio.h>
#include <windows.h>
#include <GL/glew.h>
#include <GL/wglew.h>
#include <assert.h>
#include <vector>
#include <string>
using namespace std;
extern "C"{
static HGLRC ctx = NULL;
__declspec(dllexport) bool init()
{
HWND hwnd = NULL;
HINSTANCE hinstance = (HINSTANCE)GetModuleHandle(NULL);
WNDCLASSA window_class;
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_GLOBALCLASS;
window_class.lpfnWndProc = DefWindowProc;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hInstance = hinstance;
window_class.hIcon = NULL;
window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
window_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
window_class.lpszMenuName = NULL;
window_class.lpszClassName = "test_class";
ATOM atom = RegisterClassA(&window_class);
hwnd = CreateWindowA("test_class", "htest", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 1, 1, 1, 1, NULL, NULL, hinstance, NULL);
if (hwnd == NULL) {
DWORD err = GetLastError();
return false;
}
HDC hDC = GetDC(hwnd);
if (hDC == NULL) {
return false;
}
PIXELFORMATDESCRIPTOR const pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_TYPE_RGBA,
0,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
0,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int pixel_format = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, pixel_format, &pfd);
ctx = wglCreateContext(hDC);
if (ctx) {
if (!wglMakeCurrent(hDC, ctx)) {
return false;
}
}
ReleaseDC(hwnd, hDC);
GLenum glew = glewInit();
return true;
}
static void check_gl_error()
{
GLenum error = glGetError();
assert(error == GL_NO_ERROR);
}
__declspec(dllexport) int getTotalMemory()
{
if (wglGetGPUIDsAMD && wglGetGPUInfoAMD)
{
UINT n = wglGetGPUIDsAMD(0, 0);
UINT * ids = new UINT[n];
UINT total_mem_mb = 0;
wglGetGPUIDsAMD(n, ids);
wglGetGPUInfoAMD(ids[0], WGL_GPU_RAM_AMD, GL_UNSIGNED_INT, sizeof(UINT), &total_mem_mb);
delete[] ids;
return total_mem_mb;
}
return -1;
}
__declspec(dllexport) float getAvailableMemory()
{
int available = -1;
if (wglGetGPUIDsAMD && wglGetGPUInfoAMD)
{
UINT n = wglGetGPUIDsAMD(0, 0);
UINT * ids = new UINT[n];
wglGetGPUIDsAMD(n, ids);
GLint nCurAvailMemoryInKB = 0;
glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI,
&nCurAvailMemoryInKB);
available = nCurAvailMemoryInKB;
//delete[] ids;
}
return available;
}
}
Так как у меня нет карты ATI для тестирования, я думаю, первое wglGetGPUIDsAMD
Вызов возвращает 0, вы выделяете массив длиной 0 (который работает) и в конце вы пытаетесь удалить его (который выбрасывает). Где-то посередине вы перезаписываете память вокруг этого указателя данными (таким образом, повреждая охрану и заставляя VS бросать).
Теперь, глядя на то, что вы на самом деле делаете с этим массивом, или на знание того, сколько у вас графических процессоров, вы никогда не используете ни один из них. Вы можете буквально удалить оба вызова wglGetGPUIDsAMD
и распределение / освобождение массива, и просто вызвать glGetIntegerv
,