Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Этапы алгоритма моделирования, исполняемые на 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-07; Просмотров: 325; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.026 сек.