Обновление POCGL

This commit is contained in:
SunSerega 2020-02-05 07:16:32 +02:00
parent e87ee09e77
commit 44d6d8f627
17 changed files with 58391 additions and 23607 deletions

View file

@ -11,26 +11,10 @@ uses System.Drawing;
uses System;
uses OpenGL;
{$apptype windows} // убираем консоль
{$apptype windows} // убирает консоль
var gl: OpenGL.gl;
{$region Buffer}
function InitBuffer(sz: integer; data: IntPtr): BufferName;
begin
gl.CreateBuffers(1, Result);
gl.NamedBufferData(Result, new UIntPtr(sz), data, BufferDataUsage.STATIC_DRAW);
end;
function InitBuffer(sz: integer; data: pointer) := InitBuffer(sz, IntPtr(data));
function InitBuffer<T>(sz: integer; var data: T) := InitBuffer(sz, @data);
function InitBuffer<T>(data: array of T) := InitBuffer(data.Length*System.Runtime.InteropServices.Marshal.SizeOf&<T>, data[0]);
{$endregion Buffer}
{$region Shader}
function InitShader(fname: string; st: ShaderType): ShaderName;
@ -39,40 +23,35 @@ begin
var source := ReadAllText(fname);
// в данной версии модуля OpenGL параметры принимающие массив строк - не поддерживаются
// поэтому надо ручками преобразовывать управляемую строку в неуправляемую с кодировкой ANSI
var source_strptr := System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(source);
var source_len := source.Length;
gl.ShaderSource(Result, 1, source_strptr, source_len);
// и обязательно освобождаем память, иначе снова утечка памяти
System.Runtime.InteropServices.Marshal.FreeHGlobal(source_strptr);
gl.ShaderSource(Result, 1,
new string[](source),
new integer[](source.Length)
);
gl.CompileShader(Result);
// получаем состояние успешности компиляции
// 1=успешно
// 0=ошибка
var comp_ok: integer;
gl.GetShaderiv(Result, ShaderInfoType.COMPILE_STATUS, comp_ok);
if comp_ok <> 1 then
gl.GetShaderiv(Result, ShaderParameterName.COMPILE_STATUS, comp_ok);
if comp_ok = 0 then
begin
// узнаём нужную длинную строки
var l: integer;
gl.GetShaderiv(Result, ShaderInfoType.INFO_LOG_LENGTH, l);
gl.GetShaderiv(Result, ShaderParameterName.INFO_LOG_LENGTH, l);
// выделяем достаточно памяти чтоб сохранить строку
var ptr := System.Runtime.InteropServices.Marshal.AllocHGlobal(l);
// получаем строку логов
gl.GetShaderInfoLog(Result, l, nil, ptr);
gl.GetShaderInfoLog(Result, l, IntPtr.Zero, ptr);
// преобразовываем в управляемую строку
var log := System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptr);
writeln(log);
Writeln(log);
// и опять же, в конце обязательно освобождаем памяти, чтоб не было утечек памяти
// и в конце обязательно освобождаем памяти, чтобы не было утечек памяти
System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
end;
@ -87,27 +66,26 @@ begin
Result := gl.CreateProgram;
gl.AttachShader(Result, vertex_shader);
if fragment_shader<>0 then gl.AttachShader(Result, fragment_shader);
if fragment_shader<>ShaderName.Zero then gl.AttachShader(Result, fragment_shader);
gl.LinkProgram(Result);
// всё то же самое что и у шейдеров
var link_ok: integer;
gl.GetProgramiv(Result, ProgramInfoType.LINK_STATUS, link_ok);
if link_ok <> 1 then
gl.GetProgramiv(Result, ProgramPropertyARB.LINK_STATUS, link_ok);
if link_ok = 0 then
begin
var l: integer;
gl.GetProgramiv(Result, ProgramInfoType.INFO_LOG_LENGTH, l);
gl.GetProgramiv(Result, ProgramPropertyARB.INFO_LOG_LENGTH, l);
var ptr := System.Runtime.InteropServices.Marshal.AllocHGlobal(l);
gl.GetProgramInfoLog(Result, l, nil, ptr);
gl.GetProgramInfoLog(Result, l, IntPtr.Zero, ptr);
var log := System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptr);
writeln(log);
Writeln(log);
System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
end;
end;
{$endregion Program}
@ -133,38 +111,60 @@ begin
{$region Настройка глобальных параметров OpenGL}
// при создании экземпляра OpenGL.gl инициализируются некоторые функции
// это необходимо для всех функций из OpenGL1.2 и выше, потому что они локальные для контекста OpenGL
// При создании экземпляра OpenGL.gl инициализируются некоторые функции
// Это необходимо для всех функций из OpenGL1.2 и выше, потому что они локальны для контекста OpenGL
gl := new OpenGL.gl;
{$endregion Настройка глобальных параметров OpenGL}
{$region Инициализация переменных}
var vertex_pos_buffer := InitBuffer(ArrGen(3, i->
begin
var rot := i * Pi * 2 / 3;
Result := new Vec2f(
Sin(rot),
Cos(rot) + dy
);
end));
var vertex_clr_buffer := InitBuffer(new Vec3f[](
new Vec3f(1,0,0),
new Vec3f(0,1,0),
new Vec3f(0,0,1)
));
var vertex_pos_buffer: BufferName;
gl.CreateBuffers(1, vertex_pos_buffer);
gl.NamedBufferData(
vertex_pos_buffer,
new IntPtr(3*sizeof(Vec2f)),
ArrGen(3, i->
begin
var rot := i * Pi * 2 / 3;
Result := new Vec2f(
Sin(rot),
Cos(rot) + dy
);
end),
VertexBufferObjectUsage.STATIC_DRAW
);
var element_buffer := InitBuffer(new byte[](
0,1,2
));
var vertex_clr_buffer: BufferName;
gl.CreateBuffers(1, vertex_clr_buffer);
gl.NamedBufferData(
vertex_clr_buffer,
new IntPtr(3*sizeof(Vec3f)),
new Vec3f[](
new Vec3f(1,0,0),
new Vec3f(0,1,0),
new Vec3f(0,0,1)
),
VertexBufferObjectUsage.STATIC_DRAW
);
var element_buffer: BufferName;
gl.CreateBuffers(1, element_buffer);
gl.NamedBufferData(
element_buffer,
new IntPtr(3*sizeof(byte)),
new byte[](
0,1,2
),
VertexBufferObjectUsage.STATIC_DRAW
);
var vertex_shader := InitShader('Rot Triangle 1.vertex.glsl', ShaderType.VERTEX_SHADER);
// var fragment_shader := InitShader('fragment.glsl', ShaderType.FRAGMENT_SHADER);
var sprog := InitProgram(vertex_shader, 0 {fragment_shader});
var sprog := InitProgram(vertex_shader, ShaderName.Zero {fragment_shader});
var uniform_rot_k := gl.GetUniformLocation(sprog, 'rot_k');
@ -179,7 +179,7 @@ begin
while true do
begin
// очищаем окно в начале перерисовки
gl.Clear(BufferTypeFlags.COLOR_BUFFER_BIT);
gl.Clear(ClearBufferMask.COLOR_BUFFER_BIT);
@ -187,34 +187,34 @@ begin
gl.Uniform1f(uniform_rot_k, Cos( t.Elapsed.Ticks * 0.0000002 ) );
gl.BindBuffer(BufferBindType.ARRAY_BUFFER, vertex_pos_buffer);
gl.BindBuffer(BufferTargetARB.ARRAY_BUFFER, vertex_pos_buffer);
gl.VertexAttribPointer(
attribute_position,
2,
DataType.FLOAT,
VertexAttribPointerType.FLOAT,
false,
8,
nil
IntPtr.Zero
);
gl.EnableVertexAttribArray(attribute_position);
gl.BindBuffer(BufferBindType.ARRAY_BUFFER, vertex_clr_buffer);
gl.BindBuffer(BufferTargetARB.ARRAY_BUFFER, vertex_clr_buffer);
gl.VertexAttribPointer(
attribute_color,
3,
DataType.FLOAT,
VertexAttribPointerType.FLOAT,
false,
12,
nil
IntPtr.Zero
);
gl.EnableVertexAttribArray(attribute_color);
gl.BindBuffer(BufferBindType.ELEMENT_ARRAY_BUFFER, element_buffer);
gl.BindBuffer(BufferTargetARB.ELEMENT_ARRAY_BUFFER, element_buffer);
gl.DrawElements(
PrimitiveType.TRIANGLES,
3,
DataType.UNSIGNED_BYTE,
pointer(nil)
DrawElementsType.UNSIGNED_BYTE,
IntPtr.Zero
);
gl.DisableVertexAttribArray(attribute_position);
@ -225,7 +225,7 @@ begin
// получаем тип последней ошибки
var err := gl.GetError;
// и если ошибка есть - выводим её
if err.val<>ErrorCode.NO_ERROR then writeln(err);
if err<>ErrorCode.NO_ERROR then Writeln(err);
gl.Finish;
// EndFrame меняет местами буферы и ждёт vsync

View file

@ -9,6 +9,7 @@
body {
background-color: #F0F0F0;
margin: 0px;
overflow: hidden;
}
.page-base {
@ -86,9 +87,14 @@ body {
margin-left: 8px;
}
.spoiler-wrap {
border-left: thin solid;
border: solid;
border-width: 0px;
padding-left: 2px;
}
.spoiler-name {
border: solid;
border-width: 0px;
}
.code-block {
display: inline-block;
@ -101,6 +107,19 @@ body {
margin: 0;
position: relative;
}
.code-block-copier {
cursor: pointer;
padding: 2px;
position: absolute;
top: 0;
border: thin solid;
border-radius: 3.7px 0px 3.7px 3.7px;
box-shadow: -2px 2px 3px #0000004a;
background: linear-gradient(0deg, #f0f0f0, white);
}
.inline-code {
background: #F0F0F0;
@ -142,6 +161,10 @@ const pointed_name_color = "#d1faff";
var localStorageKey = "";
const get_style = (el)=>el.currentStyle || window.getComputedStyle(el);
var spl_resize_event = [];
/* ============================== *\
page load
\* ============================== */
@ -368,20 +391,23 @@ const on_end_folder = ()=>{
\* ============================== */
var selected_page = null;
var scroll_by_page = {};
const is_selected = (name_span)=>(!selected_page || selected_page.name_span!==name_span);
const select_page = (new_page)=>{
if (selected_page == new_page) return;
document.location.hash = new_page.tree_obj.path;
fix_element(new_page);
if (selected_page) {
let container = document.getElementById("page-display-container");
if (selected_page)
{
scroll_by_page[selected_page.tree_obj.path] = container.scrollTop;
selected_page.hidden = true;
let name_span = selected_page.name_span;
if (name_span) name_span.style.backgroundColor = "inherit";
}
document.getElementById("page-display-container-body").scrollTop = 0;
selected_page = new_page;
if (selected_page)
{
@ -396,8 +422,8 @@ const select_page = (new_page)=>{
tree_obj = tree_obj.root;
}
container.scrollTop = scroll_by_page[selected_page.tree_obj.path] || 0;
}
}
const make_smart_link = (lnk, page)=>{
@ -441,8 +467,18 @@ const fix_links = (page)=>{
const code_words_color = {
"pas": {
"keyword": ["begin", "end", "var", "uses", "as", "new", "try", "except", "on", "do", "const", "procedure", "function", "lock", "type", "class", "sizeof"],
"build-in": ["nil", "integer", "string", "object", "byte"],
"keyword": [
"begin","end", "var", "uses", "as", "new", "try", "except", "on", "do", "const",
"procedure", "function", "lock", "type", "class","record", "sizeof","typeof", "external",
"static", "array", "where", "or","and", "public","private", "property","constructor", "default",
"of", "if","then","else", "div","mod", "extensionmethod", "while",
],
"build-in": [
"nil", "self", "true", "false",
"string","char", "object", "pointer", "single","real",
"shortint", "smallint", "integer", "int64",
"byte", "word", "longword", "cardinal", "uint64",
],
"red": ["ToDo"],
},
"cl-c": {
@ -465,19 +501,21 @@ const fix_element = (page)=>{
let wrap = document.createElement('p');
wrap.className = "spoiler-wrap";
wrap.update = ()=>{
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
wrap.style.border = spoiler.hidden ? "none" : null;
wrap.style.marginLeft = spoiler.hidden ? "1px" : null;
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
wrap.style.borderLeftWidth = spoiler.hidden ? 0 : 1;
wrap.name_span.style.borderBottomWidth = spoiler.hidden ? 1 : 0;
wrap.style.marginLeft = spoiler.hidden ? 1 : 0;
}
wrap.state_span = document.createElement("span");
wrap.update();
wrap.append(wrap.state_span);
wrap.name_span = document.createElement("span");
wrap.name_span.className = "spoiler-name";
wrap.name_span.innerHTML = spoiler.getAttribute("summary");
wrap.append(wrap.name_span);
wrap.update();
wrap.reverse_state = ()=>{
spoiler.hidden = !spoiler.hidden;
wrap.update();
@ -497,6 +535,8 @@ const fix_element = (page)=>{
{
let w_to_regex = (w)=>`(?<!\\w)${w}(?!\\w)`;
let code_html = code.innerHTML;
// Автоопределение языка кода
if (!code.className)
{
@ -509,7 +549,7 @@ const fix_element = (page)=>{
for (let wordt in code_words_color[lang_name])
for (let w of code_words_color[lang_name][wordt])
{
var m = code.innerHTML.match(new RegExp( w_to_regex(w), "gi" ));
var m = code_html.match(new RegExp( w_to_regex(w), "gi" ));
if (m) c += m.length;
}
@ -534,13 +574,13 @@ const fix_element = (page)=>{
let curr_cw = code_words_color[lang];
if (!curr_cw) curr_cw = code_words_color["default"];
for (let wordt in curr_cw)
code.innerHTML = code.innerHTML.replace(
code_html = code_html.replace(
new RegExp(curr_cw[wordt].map(w_to_regex).join('|'),"gi"),
w=> `<span class="code-${wordt}">${w}</span>`
);
}
// Подсветка скобок
// Выделение скобок
{
var br_types = {
op: ["(", "[", "{", "&lt;", "'"],
@ -548,11 +588,27 @@ const fix_element = (page)=>{
}
for (let op in br_types)
for (let i=0; i<br_types[op].length; i++)
code.innerHTML = code.innerHTML.replace(
code_html = code_html.replace(
new RegExp('\\'+br_types[op][i], "g"),
`<span class=bracket ${ op=="op" ? "op=true" : "" } bt=${i}>${br_types[op][i]}</span>`
);
}
// Выделение первой строки
if (code.parentElement.tagName == "PRE")
{
let ind = code_html.indexOf('\n');
if (ind != code_html.length-1)
code_html = `<span class="code-first-line">${code_html.slice(0,ind)}</span>${code_html.slice(ind)}`;
}
code.innerHTML = code_html;
code.firstLine = code.children[0];
if (code.firstLine && code.firstLine.className != "code-first-line") delete code.firstLine;
// Подсветка скобок
{
let br_st = [];
for (let obj2 of code.getElementsByClassName("bracket"))
{
@ -615,6 +671,80 @@ const fix_element = (page)=>{
}
page.style.visibility = "hidden";
page.hidden = false;
for (let code of page.getElementsByTagName('code'))
{
if (code.firstLine)
{
let pre = code.parentElement;
let copy_button = document.createElement('div');
copy_button.className = "code-block-copier";
copy_button.innerText = "Копировать";
copy_button.style.visibility = "hidden";
pre.append(copy_button);
copy_button.addEventListener("click", ()=>{
if (document.selection) { // IE
var range = document.body.createTextRange();
range.moveToElementText(code);
range.select();
} else if (window.getSelection) { // other browsers
var range = document.createRange();
range.selectNode(code);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
var text = code.innerText;
navigator.clipboard.writeText(text.substring(0,text.length-1));
});
copy_button.reset_right = ()=>{
pre_st = get_style(pre);
let container = document.getElementById("page-display-container");
let x = pre.getBoundingClientRect().right - (container.getBoundingClientRect().left+container.clientWidth);
if (x<0) x = 0; else
{
let max_x = pre.offsetWidth - copy_button.offsetWidth;
if (x>max_x) x = max_x;
}
copy_button.style.right = x;
};
let try_reset_right = ()=>{
if (!copy_button.hidden)
copy_button.reset_right();
};
spl_resize_event.push(try_reset_right);
window.addEventListener("resize", try_reset_right);
pre.addEventListener("mouseenter", ()=>{
copy_button.hidden = false;
copy_button.reset_right();
});
pre.addEventListener("mouseleave", ()=>copy_button.hidden = true);
copy_button.addEventListener("mousedown", ()=>copy_button.style.background = "linear-gradient(180deg, rgb(240, 240, 240), white)");
copy_button.addEventListener("mouseup", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
copy_button.addEventListener("mouseleave", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
pre.style.minWidth =
code.firstLine.offsetWidth +
copy_button.offsetWidth +
0
;
copy_button.hidden = true;
copy_button.style.visibility = null;
}
}
page.hidden = true;
page.style.visibility = null;
}
/* ============================== *\
@ -623,11 +753,21 @@ const fix_element = (page)=>{
{
if (document.location.hash)
define_broken_lnk(
decodeURIComponent(document.location.hash.substr(1)),
{
let get_hash = ()=>decodeURIComponent(document.location.hash.substr(1));
let define_hash_lnk = ()=>define_broken_lnk(
get_hash(),
"document.location.hash",
page=>select_page(page)
);
define_hash_lnk();
window.addEventListener("hashchange", ()=>{
let hash_page = page_by_path[get_hash()];
if (hash_page)
select_page(hash_page); else
define_hash_lnk();
});
}
let page_select = document.getElementById("page-select");
let page_display = document.getElementById("page-display");
@ -640,8 +780,8 @@ const fix_element = (page)=>{
{
let par = cont.parentElement;
par.update_cont = (w)=>{
cont.style.width = w-15 + "px";
cont.style.height = wh-15 + "px";
cont.style.width = w-15;
cont.style.height = wh-15;
};
}
@ -666,10 +806,13 @@ const fix_element = (page)=>{
page_select.update_cont(spl_X);
page_display.update_cont(w2);
for (let handler of spl_resize_event)
handler();
}
reset_spl();
window.onresize = ()=>reset_spl();
window.addEventListener("resize", ()=>reset_spl());
splitter.addEventListener("dblclick", ()=>{
let w = 0;
@ -679,7 +822,7 @@ const fix_element = (page)=>{
if (n.clientWidth>w) w = n.clientWidth;
let get_margin = (el)=>{
let style = el.currentStyle || window.getComputedStyle(el);
let style = get_style(el);
return parseFloat(style.marginLeft) + parseFloat(style.marginRight);
}
@ -726,7 +869,7 @@ window.onload = ()=>{
Вместо этого надо использовать операции с очередями (например, сложение и умножение очередей)</p>
<p>Справка модуля <code>OpenCL</code> отсутствует. Вместо неё смотрите:</p>
<ul>
<li><a href="../%D0%93%D0%B0%D0%B9%D0%B4%20%D0%BF%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8E%20OpenCL%20%D0%B8%20OpenGL.html">Общий гайд по использованию модулей <code>OpenCL</code> и <code>OpenGL</code></a></li>
<li><a href="%D0%93%D0%B0%D0%B9%D0%B4%20%D0%BF%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8E%20OpenGL%20%D0%B8%20OpenCL.html">Общий гайд по использованию модулей <code>OpenGL</code> и <code>OpenCL</code></a></li>
<li><a href="https://www.khronos.org/registry/OpenCL/">Контейнер справок библиотеки <code>OpenCL</code>, на которой основан модуль <code>OpenCL</code></a></li>
</ul>
<p>Если в справке или модуле найдена ошибка, или чего-либо не хватает - пишите в <a href="https://github.com/SunSerega/POCGL/issues">issue</a>.</p>
@ -734,26 +877,26 @@ window.onload = ()=>{
<script>on_page_added(document.getElementById("page-1"))</script>
<div id="page-2" page_name="Термины, которые часто путают новички" hidden=true>
<ul>
<li><p>CPU — Центральное Процессорное Устройство (процессор)</p>
<li><p>CPU — Центральное Процессорное Устройство (процессор);</p>
</li>
<li><p>GPU — Графическое Процессорное Устройство (видеокарта)</p>
<li><p>GPU — Графическое Процессорное Устройство (видеокарта);</p>
</li>
<li><p>Команда — запрос на выполнение чего-либо. К примеру:</p>
<ul>
<li>Запрос на запуск программы на GPU</li>
<li>Запрос на начало чтения данных из памяти GPU в оперативную память</li>
<li>Запрос на запуск программы на GPU;</li>
<li>Запрос на начало чтения данных из памяти GPU в оперативную память;</li>
</ul>
<p><strong>Называть процедуры и функции командами ошибочно!</strong></p>
</li>
<li><p>Подпрограмма — процедура или функция</p>
<li><p>Подпрограмма — процедура или функция;</p>
</li>
<li><p>Метод — особая подпрограмма, вызываемая через экземпляр</p>
<li><p>Метод — особая подпрограмма, вызываемая через экземпляр:</p>
<ul>
<li>К примеру, метод <code>Context.SyncInvoke</code> выглядит в коде как <code>cont.SyncInvoke(...)</code>, где <code>cont</code> — переменная типа <code>Context</code></li>
<li>К примеру, метод <code>Context.SyncInvoke</code> выглядит в коде как <code>cont.SyncInvoke(...)</code>, где <code>cont</code> — переменная типа <code>Context</code>;</li>
</ul>
</li>
</ul>
<p>Остальные непонятные термины можно найти в справке <code>PascalABC.NET</code> или в интернете</p>
<p>Остальные непонятные термины можно найти в справке <code>PascalABC.NET</code> или в интернете.</p>
</div>
<script>on_page_added(document.getElementById("page-2"))</script>
<script>on_end_folder()</script>
@ -771,7 +914,7 @@ window.onload = ()=>{
Если <code>Context.Default = nil</code> - переустановите графические драйверы.</p>
<hr />
<p><code>Context.Default</code> можно перезаписывать.</p>
<p>Используйте эту возможность только если во всей программе нужет общий контекст, но не стандартный.</p>
<p>Используйте эту возможность только если во всей программе нужен общий контекст, но не стандартный.</p>
<p>Частая перезапись <code>Context.Default</code> может привести к созданию сложно-ловимых багов в ваших программах.</p>
<hr />
<p>Операции, у которых невозможно указать контекст, всегда используют <code>Context.Default</code>.</p>
@ -928,6 +1071,7 @@ if cq=nil then
Writeln('Очередь не константная') else
Writeln($'Очередь была создана из значения {cq.Val}');
</code></pre>
<hr />
<p><code>CommandQueueBase</code> также можно создать из значения, но для этого тип значения должен быть <code>Object</code>:</p>
<pre><code>var q: CommandQueueBase := 5 as object;
</code></pre>
@ -943,14 +1087,14 @@ if cq=nil then
<p>Иногда между командами для GPU надо вставить выполнение обычного кода на CPU.
А разрывать для этого очередь на две части - плохо, потому что
одна целая очередь всегда выполнится быстрее двух её частей.</p>
<p>Для таких случае существуют глобальные подпрограммы HFQ и HPQ:</p>
<p>Для таких случае существуют глобальные подпрограммы <code>HFQ</code> и <code>HPQ</code>:</p>
<p>HFQ — Host Function Queue<br />
HPQ — Host Procedure Queue<br />
(Хост в контексте OpenCL - это CPU, потому что с него посылаются команды для GPU)</p>
<p>Они возвращают очередь, выполняющую код (функцию/процедуру соотвественно) на CPU.<br />
Подробнее уже описано
<a path="../Возвращаемое значение очередей/">
на предыдущей странице
на странице выше
</a>
.</p>
</div>
@ -969,7 +1113,8 @@ begin
var q1 := HPQ(()-&gt;
begin
// lock необходим чтобы при параллельном выполнении два потока не пытались использовать вывод одновременно. Иначе выведет кашу
// lock необходим чтобы при параллельном выполнении два потока
// не пытались использовать вывод одновременно. Иначе выведет кашу
lock output do Writeln('Очередь 1 начала выполняться');
Sleep(500);
lock output do Writeln('Очередь 1 закончила выполняться');
@ -1013,11 +1158,11 @@ begin
// А точнее их перегрузку, первый параметр которой - функция преобразования
Context.Default.SyncInvoke(
CombineSyncQueue(
results-&gt;results.JoinIntoString, // функция преобразования
results-&gt;results.JoinToString, // функция преобразования
q1, q2
)
).Println;
// Теперь выводит строку &quot;1 2&quot;. Это то же самое, что вернёт &quot;Arr(1,2).JoinIntoString&quot;
// Теперь выводит строку &quot;1 2&quot;. Это то же самое, что вернёт &quot;Arr(1,2).JoinToString&quot;
end.
</code></pre>
@ -1053,7 +1198,8 @@ Context.Default.SyncInvoke( Q4.Cast&amp;&lt;t2&gt; );
// Можно, потому что t2 наследует от t1
Context.Default.SyncInvoke( Q5.Cast&amp;&lt;t1&gt; );
</code></pre>
<p>Ну а если эти ограничения не подходят - остаётся только <code>.ThenConvert</code>. Он позволяет указать любой алгоритм преобразования, но и требует бОльшей производительности:</p>
<p>Ну а если эти ограничения не подходят - остаётся только <code>.ThenConvert</code>.
Он позволяет указать любой алгоритм преобразования, но работает медленнее:</p>
<pre><code>uses OpenCLABC;
begin
@ -1183,13 +1329,13 @@ var q := b.NewQueue
</code></pre>
<p>(вообще callback AddProc'а принимает исходный буфер/kernel параметром, что делает его более похожим на <code>.ThenConvert</code>, чем <code>HPQ</code>)</p>
<p>Эти методы не имеют незаменимых применений, но позволяют сделать код значительно читабельнее.</p>
<p>Кроме того, будьте осторожны, защиты от дурака для такого случая - отсутствует:</p>
<p>Кроме того, будьте осторожны, защита от дурака для такого случая - отсутствует:</p>
<pre><code>var q := b.NewQueue;
q.AddQueue(q);
</code></pre>
<p>Все <code>.Add*</code> методы добавляют команды в существующую очередь, а не создают новую.
Поэтому очередь, созданная предыдущим кодом при попытке выполнения начнёт циклически запускать саму себя.
Но это вызовет скорее не зависание, а переполнение стека (что, в целом, не лучше).</p>
Но это вызовет скорее не зависание, а переполнение стека (что, впрочем, не лучше).</p>
</div>
<script>on_page_added(document.getElementById("page-14"))</script>
<div id="page-15" page_name="Из ожидания очередей" hidden=true>
@ -1299,7 +1445,7 @@ begin
var t1 := Context.Default.BeginInvoke(
WaitFor(Q1) +
WaitFor(Q1) // второго запуска Q1 никогда не произойдёт, поэтому это зависнет
WaitFor(Q1) // второй запуск Q1 никогда не произойдёт, поэтому это зависнет
);
Context.Default.BeginInvoke(Q1);
@ -1307,7 +1453,7 @@ begin
end.
</code></pre>
<hr />
<p>Cчётчик создаётся для каждой пары [ожидаемой очереди] и [вызова <code>Context.BeginInvoke</code>] для ожидающей очереди.
<p>Cчётчик создаётся для каждой пары [ожидаемой очереди] и [вызова <code>Context.BeginInvoke</code> с ожидающей очередью].
То есть это тоже сработает:</p>
<pre><code>uses OpenCLABC;
@ -1363,15 +1509,15 @@ end.
</code></pre>
<hr />
<p>И последнее что надо знать - <code>Wait-Any</code> очередь хоть и ожидает выполнения любой одной очереди из списка,
но отнимает 1 от счётчиков всех ожидаемых очередей из того списка.</p>
но отнимает 1 от счётчиков всех ожидаемых очередей из своего списка.</p>
</div>
<script>on_page_added(document.getElementById("page-15"))</script>
<div id="page-16" page_name="Не создавая явно" hidden=true>
<p>Передавать команды по одной, когда их несколько - ужасно медленно!<br />
Но нередко бывает так, что команда всего одна. Или для отладки надо одноразово выполнить одну команду.</p>
<p>Для таких случаев можно создавать очередь неявно:<br />
У каждого метода очереди, создаваемой с <code>.NewQueue</code> есть дублирующий метод в оригинальном объекте.
Такие методы сами создают новую очередь, добавляют в неё одну соответствующую команду и выполняют полученную очередь в <code>Context.Default.SyncInvoke(...)</code>.</p>
У каждого <code>.Add*</code> метода есть дублирующий метод в оригинальном объекте. Такие методы сами создают
новую очередь, добавляют в неё одну соответствующую команду и выполняют полученную очередь в <code>Context.Default.SyncInvoke(...)</code>.</p>
<p>Обычный код с очередями:</p>
<pre><code>uses OpenCLABC;
@ -1422,9 +1568,9 @@ begin
end.
</code></pre>
<p>Кроме того, у типа <code>Buffer</code> есть дополнительные методы <code>Buffer.Get...</code>.
<p>Кроме того, у типа <code>Buffer</code> есть дополнительные методы <code>Buffer.Get*</code>.
Соответствующих методов у очередей — нет (<code>ToDo</code> возможно, в будущем появятся).</p>
<p>Методы <code>.Get...</code> создают новый объект типа записи, массива или выделяют область неуправляемой памяти,
<p>Методы <code>.Get*</code> создают новый объект типа записи, массива или выделяют область неуправляемой памяти,
читают в полученный объект содержимое буфера и возвращают этот объект.
Они также используют неявную очередь (для чтения буфера).</p>
</div>
@ -1495,8 +1641,8 @@ begin
end.
</code></pre>
<p>Все очереди-параметры начинают выполнятся сразу при вызове метода <code>Context.BeginInvoke</code>, не ожидая других очередей.</p>
<p>Обычно очереди-параметры используются при вызове kernel'а,
<p>Все вложенные очереди начинают выполнятся сразу при вызове метода <code>Context.BeginInvoke</code>, не ожидая других очередей.</p>
<p>Обычно вложенные очереди используются при вызове kernel'а,
когда надо записать что-то в буфер прямо перед вызовом kernel'а.</p>
</div>
<script>on_start_folder("Вложенные очереди", document.getElementById("page-18"))</script>
@ -1514,9 +1660,9 @@ end.
<p>Когда на GPU выделяется память - она <strong>НЕ</strong> очищается, а значит содержит мусорные данные.</p>
<p>Если метод <code>Buffer.Init</code> не был вызван до первой операции чтения/записи - он будет вызван автоматически.
В таком случае в качестве контекста в котором выделяется память берётся тот,
для которого вызвали <code>.BeginInvoke</code>, который запустил команду чтения/записи буфера.</p>
на котором вызвали <code>.BeginInvoke</code>, который запустил команду чтения/записи буфера.</p>
<p>Память на GPU можно моментально освободить, вызвав метод <code>Buffer.Dispose</code>.
Но если снова использовать буфер, у которого освободили память - память опять выделится.</p>
Но если снова использовать буфер, у которого освободили память - память заново выделится.</p>
<p>Если сборщик мусора удаляет объект типа <code>Buffer</code> - <code>.Dispose</code> вызывается автоматически.</p>
</div>
<script>on_start_folder("Буфер (Buffer)", document.getElementById("page-19"))</script>
@ -1622,17 +1768,19 @@ begin
var A := new Buffer( 10 * sizeof(integer) ); // буфер на 10 чисел типа &quot;integer&quot;
// 'TEST' - имя подпрограммы-кёрнела из .cl файла. Регистр важен!
// 'TEST' - имя подпрограммы-kernel'а из .cl файла. Регистр важен!
var kernel := code['TEST'];
kernel.Exec1(10, // используем 10 потоков
A.NewQueue.AddFillValue(1) // заполняем весь буфер единичками, прямо перед выполнением
as CommandQueue&lt;Buffer&gt; //ToDo нужно только из за issue компилятора #1981, иначе получаем странную ошибку. Когда исправят - можно будет убрать
//ToDo нужно только из за issue компилятора #1981
as CommandQueue&lt;Buffer&gt;
);
A.GetArray1&amp;&lt;integer&gt;.Println; // читаем весь буфер как одномерный массив с элементами типа &quot;integer&quot; и сразу выводим
// читаем весь буфер как одномерный массив с элементами типа &quot;integer&quot; и сразу выводим
A.GetArray1&amp;&lt;integer&gt;.Println;
end.
</code></pre>

View file

@ -9,6 +9,7 @@
body {
background-color: #F0F0F0;
margin: 0px;
overflow: hidden;
}
.page-base {
@ -86,9 +87,14 @@ body {
margin-left: 8px;
}
.spoiler-wrap {
border-left: thin solid;
border: solid;
border-width: 0px;
padding-left: 2px;
}
.spoiler-name {
border: solid;
border-width: 0px;
}
.code-block {
display: inline-block;
@ -101,6 +107,19 @@ body {
margin: 0;
position: relative;
}
.code-block-copier {
cursor: pointer;
padding: 2px;
position: absolute;
top: 0;
border: thin solid;
border-radius: 3.7px 0px 3.7px 3.7px;
box-shadow: -2px 2px 3px #0000004a;
background: linear-gradient(0deg, #f0f0f0, white);
}
.inline-code {
background: #F0F0F0;
@ -142,6 +161,10 @@ const pointed_name_color = "#d1faff";
var localStorageKey = "";
const get_style = (el)=>el.currentStyle || window.getComputedStyle(el);
var spl_resize_event = [];
/* ============================== *\
page load
\* ============================== */
@ -368,20 +391,23 @@ const on_end_folder = ()=>{
\* ============================== */
var selected_page = null;
var scroll_by_page = {};
const is_selected = (name_span)=>(!selected_page || selected_page.name_span!==name_span);
const select_page = (new_page)=>{
if (selected_page == new_page) return;
document.location.hash = new_page.tree_obj.path;
fix_element(new_page);
if (selected_page) {
let container = document.getElementById("page-display-container");
if (selected_page)
{
scroll_by_page[selected_page.tree_obj.path] = container.scrollTop;
selected_page.hidden = true;
let name_span = selected_page.name_span;
if (name_span) name_span.style.backgroundColor = "inherit";
}
document.getElementById("page-display-container-body").scrollTop = 0;
selected_page = new_page;
if (selected_page)
{
@ -396,8 +422,8 @@ const select_page = (new_page)=>{
tree_obj = tree_obj.root;
}
container.scrollTop = scroll_by_page[selected_page.tree_obj.path] || 0;
}
}
const make_smart_link = (lnk, page)=>{
@ -441,8 +467,18 @@ const fix_links = (page)=>{
const code_words_color = {
"pas": {
"keyword": ["begin", "end", "var", "uses", "as", "new", "try", "except", "on", "do", "const", "procedure", "function", "lock", "type", "class", "sizeof"],
"build-in": ["nil", "integer", "string", "object", "byte"],
"keyword": [
"begin","end", "var", "uses", "as", "new", "try", "except", "on", "do", "const",
"procedure", "function", "lock", "type", "class","record", "sizeof","typeof", "external",
"static", "array", "where", "or","and", "public","private", "property","constructor", "default",
"of", "if","then","else", "div","mod", "extensionmethod", "while",
],
"build-in": [
"nil", "self", "true", "false",
"string","char", "object", "pointer", "single","real",
"shortint", "smallint", "integer", "int64",
"byte", "word", "longword", "cardinal", "uint64",
],
"red": ["ToDo"],
},
"cl-c": {
@ -465,19 +501,21 @@ const fix_element = (page)=>{
let wrap = document.createElement('p');
wrap.className = "spoiler-wrap";
wrap.update = ()=>{
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
wrap.style.border = spoiler.hidden ? "none" : null;
wrap.style.marginLeft = spoiler.hidden ? "1px" : null;
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
wrap.style.borderLeftWidth = spoiler.hidden ? 0 : 1;
wrap.name_span.style.borderBottomWidth = spoiler.hidden ? 1 : 0;
wrap.style.marginLeft = spoiler.hidden ? 1 : 0;
}
wrap.state_span = document.createElement("span");
wrap.update();
wrap.append(wrap.state_span);
wrap.name_span = document.createElement("span");
wrap.name_span.className = "spoiler-name";
wrap.name_span.innerHTML = spoiler.getAttribute("summary");
wrap.append(wrap.name_span);
wrap.update();
wrap.reverse_state = ()=>{
spoiler.hidden = !spoiler.hidden;
wrap.update();
@ -497,6 +535,8 @@ const fix_element = (page)=>{
{
let w_to_regex = (w)=>`(?<!\\w)${w}(?!\\w)`;
let code_html = code.innerHTML;
// Автоопределение языка кода
if (!code.className)
{
@ -509,7 +549,7 @@ const fix_element = (page)=>{
for (let wordt in code_words_color[lang_name])
for (let w of code_words_color[lang_name][wordt])
{
var m = code.innerHTML.match(new RegExp( w_to_regex(w), "gi" ));
var m = code_html.match(new RegExp( w_to_regex(w), "gi" ));
if (m) c += m.length;
}
@ -534,13 +574,13 @@ const fix_element = (page)=>{
let curr_cw = code_words_color[lang];
if (!curr_cw) curr_cw = code_words_color["default"];
for (let wordt in curr_cw)
code.innerHTML = code.innerHTML.replace(
code_html = code_html.replace(
new RegExp(curr_cw[wordt].map(w_to_regex).join('|'),"gi"),
w=> `<span class="code-${wordt}">${w}</span>`
);
}
// Подсветка скобок
// Выделение скобок
{
var br_types = {
op: ["(", "[", "{", "&lt;", "'"],
@ -548,11 +588,27 @@ const fix_element = (page)=>{
}
for (let op in br_types)
for (let i=0; i<br_types[op].length; i++)
code.innerHTML = code.innerHTML.replace(
code_html = code_html.replace(
new RegExp('\\'+br_types[op][i], "g"),
`<span class=bracket ${ op=="op" ? "op=true" : "" } bt=${i}>${br_types[op][i]}</span>`
);
}
// Выделение первой строки
if (code.parentElement.tagName == "PRE")
{
let ind = code_html.indexOf('\n');
if (ind != code_html.length-1)
code_html = `<span class="code-first-line">${code_html.slice(0,ind)}</span>${code_html.slice(ind)}`;
}
code.innerHTML = code_html;
code.firstLine = code.children[0];
if (code.firstLine && code.firstLine.className != "code-first-line") delete code.firstLine;
// Подсветка скобок
{
let br_st = [];
for (let obj2 of code.getElementsByClassName("bracket"))
{
@ -615,6 +671,80 @@ const fix_element = (page)=>{
}
page.style.visibility = "hidden";
page.hidden = false;
for (let code of page.getElementsByTagName('code'))
{
if (code.firstLine)
{
let pre = code.parentElement;
let copy_button = document.createElement('div');
copy_button.className = "code-block-copier";
copy_button.innerText = "Копировать";
copy_button.style.visibility = "hidden";
pre.append(copy_button);
copy_button.addEventListener("click", ()=>{
if (document.selection) { // IE
var range = document.body.createTextRange();
range.moveToElementText(code);
range.select();
} else if (window.getSelection) { // other browsers
var range = document.createRange();
range.selectNode(code);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
var text = code.innerText;
navigator.clipboard.writeText(text.substring(0,text.length-1));
});
copy_button.reset_right = ()=>{
pre_st = get_style(pre);
let container = document.getElementById("page-display-container");
let x = pre.getBoundingClientRect().right - (container.getBoundingClientRect().left+container.clientWidth);
if (x<0) x = 0; else
{
let max_x = pre.offsetWidth - copy_button.offsetWidth;
if (x>max_x) x = max_x;
}
copy_button.style.right = x;
};
let try_reset_right = ()=>{
if (!copy_button.hidden)
copy_button.reset_right();
};
spl_resize_event.push(try_reset_right);
window.addEventListener("resize", try_reset_right);
pre.addEventListener("mouseenter", ()=>{
copy_button.hidden = false;
copy_button.reset_right();
});
pre.addEventListener("mouseleave", ()=>copy_button.hidden = true);
copy_button.addEventListener("mousedown", ()=>copy_button.style.background = "linear-gradient(180deg, rgb(240, 240, 240), white)");
copy_button.addEventListener("mouseup", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
copy_button.addEventListener("mouseleave", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
pre.style.minWidth =
code.firstLine.offsetWidth +
copy_button.offsetWidth +
0
;
copy_button.hidden = true;
copy_button.style.visibility = null;
}
}
page.hidden = true;
page.style.visibility = null;
}
/* ============================== *\
@ -623,11 +753,21 @@ const fix_element = (page)=>{
{
if (document.location.hash)
define_broken_lnk(
decodeURIComponent(document.location.hash.substr(1)),
{
let get_hash = ()=>decodeURIComponent(document.location.hash.substr(1));
let define_hash_lnk = ()=>define_broken_lnk(
get_hash(),
"document.location.hash",
page=>select_page(page)
);
define_hash_lnk();
window.addEventListener("hashchange", ()=>{
let hash_page = page_by_path[get_hash()];
if (hash_page)
select_page(hash_page); else
define_hash_lnk();
});
}
let page_select = document.getElementById("page-select");
let page_display = document.getElementById("page-display");
@ -640,8 +780,8 @@ const fix_element = (page)=>{
{
let par = cont.parentElement;
par.update_cont = (w)=>{
cont.style.width = w-15 + "px";
cont.style.height = wh-15 + "px";
cont.style.width = w-15;
cont.style.height = wh-15;
};
}
@ -666,10 +806,13 @@ const fix_element = (page)=>{
page_select.update_cont(spl_X);
page_display.update_cont(w2);
for (let handler of spl_resize_event)
handler();
}
reset_spl();
window.onresize = ()=>reset_spl();
window.addEventListener("resize", ()=>reset_spl());
splitter.addEventListener("dblclick", ()=>{
let w = 0;
@ -679,7 +822,7 @@ const fix_element = (page)=>{
if (n.clientWidth>w) w = n.clientWidth;
let get_margin = (el)=>{
let style = el.currentStyle || window.getComputedStyle(el);
let style = get_style(el);
return parseFloat(style.marginLeft) + parseFloat(style.marginRight);
}
@ -716,9 +859,9 @@ window.onload = ()=>{
}
</script>
<div id="page-1" page_name="" hidden=true>
<p><code>ToDo</code> модуля OpenGLABC пока что не существует. Когда то он появится, но пока что есть только это сообщение.</p>
<p><code>ToDo</code> модуля <code>OpenGLABC</code> пока что не существует. Когда то он появится, но пока что есть только это сообщение.</p>
<p>Если хотите понять, было ли это сообщение оставлено тут 10 лет назад и забыто - вот дата, когда автор сообщения последний раз прочитал его:<br />
08.01.2020</p>
03.02.2020</p>
</div>
<script>on_start_folder("GL ABC", document.getElementById("page-1"))</script>
<script>on_end_folder()</script>

File diff suppressed because it is too large Load diff