Студопедия Главная Случайная страница Задать вопрос

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Этапы алгоритма моделирования, исполняемые на CPU





Программа для графического процессора должна запускаться внутри полного алгоритма молекулярной динамики, остальные части которого исполняются на центральном процессоре. Ниже мы рассмотрим реализацию этого общего алгоритма на языке C# с использованием библиотеки процедур XNA2.

Для проведения расчёта на графическом процессоре во внешней, вызы­ваю­щей этот расчёт, программе, необходимо выполнить ряд операций:

· Создать объект (в DirectX – объект типа Graphics­DeviceManager), реализующий доступ к графическому процессору;

Рис. 6.6. Операции, исполняемые центральным процессором

· Выделить память (т.е., описать переменные) для массивов, в которых будут храниться входные данные, – координаты частиц и параметры потенциа­лов взаимодействия, – а также выходные данные – компоненты векторов сил, действующих на ионы;

· Представить входные данные в форме, требуемой для их передачи графи­ческому процессору;

· Выделить память для хранения координат вершин квада (описание поня­тия «квад» приведено выше) и задать значения этих координат;

· Обратиться к текстовому файлу, содержащему код шейдера (программы для графического процессора). Откомпилировать этот код и записать получен­ную программу в память, доступную графическому процессору (перечисленные задачи программируются несложно, поскольку в библиотеке XNA2 для этого есть стандартные процедуры);

· Передать графическому процессору исходные данные;

· Исполнить необходимые расчёты;

· Скопировать результат из рендер-цели для дальнейшего использова­ния в программе на центральном процессоре;

Операции, которые необходимо выполнить для организации расчёта, обобщены в блок-схеме на рис. 6.6.

6.3.2. Процедуры на C#, обеспечивающие работу с графическим процессором

Ниже приведён текст программы на C#, в котором выделены и прокоммен­тированы все перечисленные этапы. В этом тексте присутствуют и все необхо­димые вспомогательные операции, также с комментариями.

private void InitGPU()/* Подготовительные операции для расчёта на графическом процессоре */

{

//Локальная переменная, представляющая графический процессор

gpu = graphics.GraphicsDevice;

 

//Создаем текстуру размером w * h, в которой будут храниться координаты и типы частиц. Количество ячеек в этой текстуре (w*h) должно совпадать с количеством частиц в кристалле, либо превышать это количество (в последнем случае «лишние» ячейки не исполь­зуют­ся). Расчёт на GPU будет наиболее быстрым, если w и h кратны 32.

in_pos = new Texture2D(gpu, w, h, 1, TextureUsage.None, SurfaceFormat.Vector4);

 

//Создаём рендер-цель – текстуру размером w * h, в которую попадет результат рас­чета сил – в её ячейках будут храниться силы, действующие на каждый из ионов.

out_force = new RenderTarget2D(gpu, w, h, 1, SurfaceFormat.Vector4, RenderTargetUsage.PreserveContents);

 

// Задаем текстуру размером 2 * 2, с параметрами парного межчастичного потенциала

in_coefs = new Texture2D(gpu, 2, 2, 1, TextureUsage.None, SurfaceFormat.Vector4);

float[] data = new float[2 * 2 * 4];

for (int u = 0; u < 2; u++)

for (int v = 0; v < 2; v++) //здесь 2 цикла могли быть заменены одним по i от 0

//до <количества пар> - 1

{

int i = (u * 2 + v) * 4;

data[i] = (float)coefs[i++];

data[i] = (float)coefs[i++];

data[i] = (float)coefs[i++];

data[i] = (float)coefs[i++];

}

in_coefs.SetData<float>(data); //in_coefs - переменная типа Texture2D

 

//Задаем квад (вершинные и текстурные координаты, соответственно).

//Y-координата текстуры инвертирована по отношению к Y-координате вершины,

//т.к. ось Y направлена снизу вверх в пространстве вершин и сверху вниз в пространстве экрана.

 

float du = 0.5f / w, dv = 0.5f / h;

// смещения для адресации текселей по центрам

//(в случае текстур с размерами не равными степени числа 2

quad = new VertexBuffer(gpu, typeof(VertexPositionTexture), 4, BufferUsage.None); //переменная типа VertexBuffer

quad.SetData<VertexPositionTexture>(new VertexPositionTexture[] {

new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2(0 + du, 0 + dv)),

new VertexPositionTexture(new Vector3( 1, 1, 0), new Vector2(1 + du, 0 + dv)),

new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0 + du, 1 + dv)),

new VertexPositionTexture(new Vector3( 1, -1, 0), new Vector2(1 + du, 1 + dv))

}); // кубу в пространстве сопоставлены смещенные углы плоскости

gpu.Vertices[0].SetSource(quad, 0, VertexPositionTexture.SizeInBytes); //размер квада

gpu.VertexDeclaration = new VertexDeclaration(gpu, VertexPositionTexture.VertexElements); //неясно, что

 

//Задаем шейдер и его входные параметры.

//Компиляция текстового файла с шейдером

CompiledEffect e = Effect.CompileEffectFromFile("force.fx", null, null, CompilerOptions.None, TargetPlatform.Windows);

//Проверка успешности компиляции

if (!e.Success) throw new Exception(e.ErrorsAndWarnings);

//Записывает программу эффекта в память видеокарты

fx = new Effect(gpu, e.GetEffectCode(), CompilerOptions.None, null); //переменная типа Effect

//Выбирает роцедуру из кода эффекта, которую надо будет выполнять

fx.CurrentTechnique = fx.Techniques["Force"];

//Передача на видеокарту координат частиц

fx.Parameters["in_pos"].SetValue(in_pos); //видимо, in_pos и in_coefs описаны в шейдере как входные текстуры

//Передача на видеокарту параметров потенциалов взаимодействия

fx.Parameters["in_coefs"].SetValue(in_coefs);

}

private void ForceGPU()

{

int i, u, v;

 

//Задаем текстуру с координатами и типами частиц

float[] data = new float[w * h * 4];

 

/* Текстура представляет собой таблицу с размером w по горизонтали и h по вертикали.

* В каждой ячейке таблицы находится 4-х-вектор, хранящий координаты и тип ионов.

* Номер частицы в линейном массиве i вычисляется по формуле i = v * w + u

*/

for (v = 0; v < h; v++)

for (u = 0; u < w; u++)

{

i = v * w + u;

data[i * 4 + 0] = (float)pos[i * 3 + 0];

data[i * 4 + 1] = (float)pos[i * 3 + 1];

data[i * 4 + 2] = (float)pos[i * 3 + 2];

data[i * 4 + 3] = type[i] / 2f;

}

in_pos.SetData<float>(data); //in_pos - переменная типа Texture2D

 

//Задаем новую рендер-цель, сохраняя старую.

RenderTarget2D old_render_target = (RenderTarget2D)gpu.GetRenderTarget(0); //Зачем нужно преобразование типа?

gpu.SetRenderTarget(0, out_force); //out_force - переменная типа RenderTarget2D

gpu.Clear(new Color(0, 0, 0, 0)); //Обнуление сил в рендер-цели

 

fx.Begin(); //спросить, что делает Begin. Загружает в память?

for (i = 0; i < ions; i++)

{

//Обновляем ссылку на рендер-цель (необходимо для корректного выполнения операции += в шейдере)

gpu.SetRenderTarget(0, null); fx.Parameters["out_force"].SetValue(out_force.GetTexture());

gpu.SetRenderTarget(0, out_force);

//Передаем в шейдер текстурные координаты i-й частицы.

u = i % w; v = i / w; //очевидно, % - остаток от деления

fx.Parameters["u_i"].SetValue((u + 0.5f) / w); //передаётся центр ячейки

fx.Parameters["v_i"].SetValue((v + 0.5f) / h); //передаётся центр ячейки

 

//Вычисляем взаимодействие i-й частицы со всеми остальными.

fx.CurrentTechnique.Passes["force_i"].Begin();

gpu.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);

fx.CurrentTechnique.Passes["force_i"].End();

}

fx.End(); //В цикле по всем частицам заполняется одна и та же рендер-цель

 

//Восстанавливаем старую рендер-цель.

gpu.SetRenderTarget(0, old_render_target);

 

//Получаем результат из новой рендер-цели

data = new float[w * h * 4];

for (i = 0; i < 3; i++) gpu.Textures[i] = null;

out_force.GetTexture().GetData<float>(data); //out_force - массив с рендер-целью

for (v = 0; v < h; v++)

for (u = 0; u < w; u++)

{

i = v * w + u;

force[i * 3 + 0] = data[i * 4 + 0];

force[i * 3 + 1] = data[i * 4 + 1];

force[i * 3 + 2] = data[i * 4 + 2];

}

}






Дата добавления: 2014-12-06; просмотров: 232. Нарушение авторских прав

Studopedia.info - Студопедия - 2014-2017 год . (0.018 сек.) русская версия | украинская версия