OberonCore
https://forum.oberoncore.ru/

NEW для структур без метки (untagged)
https://forum.oberoncore.ru/viewtopic.php?f=29&t=5664
Страница 2 из 4

Автор:  Alexander Shiryaev [ Понедельник, 11 Апрель, 2016 02:33 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Из SDL-2.0.4/include/SDL_events.h:
Код:
/**
 *  \brief Mouse wheel event structure (event.wheel.*)
 */
typedef struct SDL_MouseWheelEvent
{
    Uint32 type;        /**< ::SDL_MOUSEWHEEL */
    Uint32 timestamp;
    Uint32 windowID;    /**< The window with mouse focus, if any */
    Uint32 which;       /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
    Sint32 x;           /**< The amount scrolled horizontally, positive to the right and negative to the left */
    Sint32 y;           /**< The amount scrolled vertically, positive away from the user and negative toward the user */
    Uint32 direction;   /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
} SDL_MouseWheelEvent;

Ну ладно, это не важно.

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 02:45 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

У меня в Обероновской обёртке был этот direction, я его теперь убрал.
SDL_version.h говорит, что версия 2.0.2. Видимо, direction добавлен в 2.0.4.

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 03:05 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Чудеса.
Код:
PROCEDURE Run;
VAR quit: BOOLEAN;
  key, code: INTEGER;
  A, B, C, D, E: SHORTCHAR;
  rr: SDL.Rect;
BEGIN
  ...
  key := SDL.FillRect(screen.surface, rr, code);
Ошибки нет. Но если убрать одну из пяти переменных: A, B, C, D, E, то ошибка будет. Видимо, когда их 5, а не 4, на них выделяется 8 байт (а не 4). А какая-то процедура из SDL2 лезет не в свою память. Только я никак не пойму, почему ошибка происходит именно на SDL_RectFill. Это ведь элементарная процедура, принимает два указателя и INTEGER, возвращает INTEGER, помечена в SDL как [stdcall] (я так понимаю, что в Блэкбоксе это [ccall], правильно? Во всяком случае, когда убираешь [ccall] лучше не становится). Поправка: там не stdcall, а SDLCALL, который объявлен так, что он либо превращается в __cdecl, если «defined(__WIN32__) и при этом не defined(__GNUC__)», либо превращается в пустоту.
2) Если передвинуть все пять переменных (A, B, C, D, E) на одну строку выше, то ошибка тоже появляется:
Код:
VAR quit: BOOLEAN;
  A, B, C, D, E: SHORTCHAR; (* вот сюда, перед key *)
  key, code: INTEGER;
  rr: SDL.Rect;
BEGIN
А вот теперь я опять не понимаю. Какая разница, где они стоят? Или BOOLEAN-таки занимает 1 байт, а не 4? Видимо, да, т. к. если число этих переменных довести до 7, ошибка не пропадает, а вот когда их 8, то ошибки нет:
Код:
VAR quit: BOOLEAN;
  A, B, C, D, E, F, H, J: SHORTCHAR; (* 8 штук + BOOLEAN = 9 -> 12 байт *)
  key, code: INTEGER;
  rr: SDL.Rect;
BEGIN
Весело :) Ошибка в обёртке к какой-то другой SDL'овской процедуре, да?

Это, кстати, не из-за Events'ов, можно эту часть вообще убрать из программы и глюки будут те же самые. Ошибка происходит до входа в событийный цикл.

Автор:  Роман М. [ Понедельник, 11 Апрель, 2016 09:01 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

kekc_leader, я так и не понял в чём смысл изобретения велосипеда. Привязка к библиотеке SDL2 существует. Разве она чем-то не устраивает? Ведь можно изменить, если так необходимо.

Автор:  Иван Денисов [ Понедельник, 11 Апрель, 2016 09:32 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

kekc_leader, это не поможет с этим конкретным багом, но я рекомендую поновее все-таки версию Блэкбокса использовать.
Либо сборки OberonCore, либо с сайта http://zinnamturm.eu/downloads.htm
Но лучше возьмите последнюю сборку Центра: http://blackboxframework.org/lastdev/zip.php
В ней добавлены в том числе возможности работы с UTF-8 "из коробки", что часто нужно для работы с внешними библиотеками.

А для решения бага, надо точно проверить отличия заголовочных файлов для винды и для Linux. У меня есть опыт, когда для MPICH отличается порядок расположения переменных в записевых типах. И это приводило к аналогичной ошибке. Стоило очень внимательно все привязки проверить и ошибка обнаружилась. Для автоматической генерации привязок есть, кстати, утилита H2O.

Автор:  Роман М. [ Понедельник, 11 Апрель, 2016 09:45 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

kekc_leader писал(а):
У меня в Обероновской обёртке был этот direction, я его теперь убрал.
SDL_version.h говорит, что версия 2.0.2. Видимо, direction добавлен в 2.0.4.
Да. Добавили ещё много чего другого.
https://github.com/spurious/SDL-mirror/ ... ew.txt#L23

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 12:05 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Роман М. писал(а):
kekc_leader, я так и не понял в чём смысл изобретения велосипеда. Привязка к библиотеке SDL2 существует. Разве она чем-то не устраивает? Ведь можно изменить, если так необходимо.
Смысл в том числе и в том, чтобы на этом примере научиться пользоваться Блэкбоксом под Линукс. Ту уже готовую привязку SDL2, что я нашёл, я не смог запустить, там нужен OpenGL, используются kernel hook'и какие-то и т.д. В общем, избыточная сложность. «Оберон-технологии» учат в том числе, что порой лучше «изобрести велосипед», чем ковыряться в развалинах чужого велосипеда. :)
Цель - создать минимальную привязку к SDL2 под Виндоус и Линукс и написать детальную инструкцию по её установке на Windows 7 и Debian 8. Следующий шаг - разобраться, как сделать так, чтобы, при запуске, Блэкбокс не показывал свои окна, а только запускал SDL (под Линуксом и под Виндоусом), заставить Блэкбокс создавать исполняемые файлы под Линуксом и под Виндоусом, опять же написать инструкцию.
Всего этого не хватает, а хотелось бы, чтобы люди втягивались в Оберон. Пока что все компиляторы либо устарели, либо не имеют настоящей полноценной документации, либо ограничены (типа, EXE можно создавать, а ELF нельзя), либо имеют глюки, которые вряд ли вообще можно исправить (как OO2C со своей агрессивной оптимизацией). Не хватает самых основных вещей.

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 12:09 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Иван Денисов писал(а):
я рекомендую поновее все-таки версию Блэкбокса использовать.
А что делать с Линуксовской версией? Её можно как-то обновить?
Иван Денисов писал(а):
А для решения бага, надо точно проверить отличия заголовочных файлов для винды и для Linux.
Уже проверил, ошибки не заметил. Придётся ещё раз перепроверять. Я захожу в /usr/include/SDL2/ и там нахожу каждую процедуру и тип в файлах *.h и сверяю.

Автор:  Alexander Shiryaev [ Понедельник, 11 Апрель, 2016 14:48 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Может это как-то связано с выравниванием rr на стеке?
Код:
StdLog.String("ADR(rr) MOD 16 = "); StdLog.Int(SYSTEM.ADR(rr) MOD 16); StdLog.Ln;

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 17:15 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Alexander Shiryaev писал(а):
Может это как-то связано с выравниванием rr на стеке?
Код:
StdLog.String("ADR(rr) MOD 16 = "); StdLog.Int(SYSTEM.ADR(rr) MOD 16); StdLog.Ln;
Когда работает (т. е. если переменная J присутсвует), ADR MOD 16 даёт 12. Когда не работает (т. е. если J убрать) - ADR MOD 16 даёт 0.
Если добавить ещё три переменные: J1, J2, J3, по прежнему даёт 12 и работает, если же добавить ещё одну - J4, опять появляется ошибка, а MOD 16 даёт 8...
Код:
PROCEDURE Run;
VAR quit: BOOLEAN;
  A, B, C, D, E, F, H, J, J1, J2, J3, J4: SHORTCHAR;
  key, code: INTEGER;
  rr: SDL.Rect;
BEGIN
Но когда всё нормально, прямоугольник рисуется правильно.

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 17:29 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

В другой процедуре (Draw), если SYSTEM.ADR(rr) MOD 16 = 4, то всё работает. Если не 4, а 0, 8 или 12, то происходит трап.
Код:
PROCEDURE Draw;
VAR i, x, y, color: INTEGER;
  (*A: ARRAY [untagged] 4 OF SHORTCHAR;*)
  rr: SDL.Rect;
  b: G.Bitmap;
BEGIN
  ...
  StdLog.String('ADR(rr) MOD 16 ='); StdLog.Int(SYSTEM.ADR(rr) MOD 16); StdLog.Ln;
  IF SDL.FillRect(screen.surface, rr, color) = 0 THEN END
Вот если эту строчку (A: ARRAY ...) раскомментировать, то оно рушится. Вместо 4 можно писать 8 или 12 (все промежуточные числа приводят к таким же значениям ADR(rr) MOD 16). А вот если написать ARRAY [untagged] 16 OF SHORTCHAR, то всё снова работает, т. к. ADR(rr) MOD 16 снова становится равным 4.
Как с этим бороться?

Автор:  Kemet [ Понедельник, 11 Апрель, 2016 17:48 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

kekc_leader, а линукс скольки разрядный?

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 17:51 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Kemet писал(а):
kekc_leader, а линукс скольки разрядный?
32-разрядный
Код:
$ uname -a
Linux saturn 3.16.0-4-686-pae #1 SMP Debian 3.16.7-ckt20-1+deb8u3 (2016-01-17) i686 GNU/Linux

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 19:59 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

У меня есть ещё более загадочная новость.
Код:
PROCEDURE Draw;
VAR i, x, y, color: INTEGER;
  (*A: ARRAY [untagged] 4 OF SHORTCHAR;*)
  rr: SDL.Rect;
  b: G.Bitmap;
BEGIN
  ...
  StdLog.String('ADR(rr) MOD 16 ='); StdLog.Int(SYSTEM.ADR(rr) MOD 16); StdLog.Ln;
  IF SDL.FillRect(screen.surface, rr, color) = 0 THEN END
Если в последней строке поменять rr на NIL, то ошибка всё равно будет появляться в тех же случаях! То есть rr вообще не используется, а длина массива A влияет на наличие ошибки.
(Для справки: если в SDL_FillRect вторым параметром передать NULL, то она закрашивает весь Surface)
Получается, наличие ошибки зависит не от местоположения экземпляра записи SDL.Rect в памяти, а от... количества памяти, занимаемого всеми переменными процедуры, из которой вызывается SDL.FillRect?

Автор:  prospero78 [ Понедельник, 11 Апрель, 2016 20:08 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Смею предположить, что нилл по разрядности отличается, либо ссылка требуется на переменную, либо что-то из этого ряда. А если тот же нилл переменной присвоить. Кстати, да. Там же структура по ссылке передаётся (вроде?)
Какая там заливка будет, если координат нет.

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 20:44 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

В том-то и дело, что всё работает замечательно, если только в VAR положить правильное количество SHORTCHAR'ов. SDL_FillRect с NIL'ом закрашивает весь экран, как он и должен.
SDL_FillRect принимает вторым параметром указатель на SDL_Rect. SDL_Rect - это struct, внутри которого 4 INTEGER'а. Всё предельно просто и всё равно что-то работает не так.
Вот оригинальный код SDL_FillRect'а (файл «src/video/SDL_fillrect.c»):
Код:
/*
 * This function performs a fast fill of the given rectangle with 'color'
 */
int
SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color)
{
    SDL_Rect clipped;
    Uint8 *pixels;

    if (!dst) {
        return SDL_SetError("Passed NULL destination surface");
    }

    /* This function doesn't work on surfaces < 8 bpp */
    if (dst->format->BitsPerPixel < 8) {
        return SDL_SetError("SDL_FillRect(): Unsupported surface format");
    }

    /* If 'rect' == NULL, then fill the whole surface */
    if (rect) {
        /* Perform clipping */
        if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) {
            return 0;
        }
        rect = &clipped;
    } else {
        rect = &dst->clip_rect;
        /* Don't attempt to fill if the surface's clip_rect is empty */
        if (SDL_RectEmpty(rect)) {
            return 0;
        }
    }

    /* Perform software fill */
    if (!dst->pixels) {
        return SDL_SetError("SDL_FillRect(): You must lock the surface");
    }

    pixels = (Uint8 *) dst->pixels + rect->y * dst->pitch +
                                     rect->x * dst->format->BytesPerPixel;

    switch (dst->format->BytesPerPixel) {
    case 1:
        {
            color |= (color << 8);
            color |= (color << 16);
#ifdef __SSE__
            if (SDL_HasSSE()) {
                SDL_FillRect1SSE(pixels, dst->pitch, color, rect->w, rect->h);
                break;
            }
#endif
            SDL_FillRect1(pixels, dst->pitch, color, rect->w, rect->h);
            break;
        }

    case 2:
        {
            color |= (color << 16);
#ifdef __SSE__
            if (SDL_HasSSE()) {
                SDL_FillRect2SSE(pixels, dst->pitch, color, rect->w, rect->h);
                break;
            }
#endif
            SDL_FillRect2(pixels, dst->pitch, color, rect->w, rect->h);
            break;
        }

    case 3:
        /* 24-bit RGB is a slow path, at least for now. */
        {
            SDL_FillRect3(pixels, dst->pitch, color, rect->w, rect->h);
            break;
        }

    case 4:
        {
#ifdef __SSE__
            if (SDL_HasSSE()) {
                SDL_FillRect4SSE(pixels, dst->pitch, color, rect->w, rect->h);
                break;
            }
#endif
            SDL_FillRect4(pixels, dst->pitch, color, rect->w, rect->h);
            break;
        }
    }

    /* We're done! */
    return 0;
}

Вот объявление этой процедуры на экспорт в файле «include/SDL_surface.h»:
Код:
extern DECLSPEC int SDLCALL SDL_FillRect
    (SDL_Surface * dst, const SDL_Rect * rect, Uint32 color);

Вот моё определение процедуры в Блэкбоксе (файл «Graph/Mod/GraphSdl.odc») и за одно определния Surface и Rect:
Код:
PROCEDURE [ccall] FillRect* ["SDL_FillRect"] (dst: Surface; VAR [nil] rect: Rect; color: INTEGER): INTEGER;

Surface* = POINTER [untagged] TO SurfaceDesc;
SurfaceDesc* = RECORD [untagged]
  flags: INTEGER;
  format*: PixelFormat; (* Это указатель *)
  (* и т. д. *)
END;

Rect* = RECORD [untagged]
  x*, y*, w*, h*: INTEGER
END;

Оригинальный SDL_Rect из файла «include/SDL_rect.h»:
Код:
typedef struct SDL_Rect
{
    int x, y;
    int w, h;
} SDL_Rect;

То есть оно принимает NIL и рисует всё правильно. И если дать ему не NIL, а Rect, то оно тоже всё принимает и всё рисует правильно. Но только если в VAR правильное количество байтов. Причём, в случае с процедурой Draw оно должно равняться (36 + 4 * n) байтам (где n = 0, 1, 2...). Вот сейчас у меня там i, x, y, color: INTEGER (16 байтов), затем ARRAY [untagged] 16 OF SHORTCHAR (ещё 16 байтов), потом Q1, Q2, Q3, Q4, Q5: INTEGER; (ещё 20 байтов). Итого: 52 и всё работает. Если уберу Q2, Q3, Q4, Q5, оставив Q1, то тоже будет всё работать. Но если уберу и Q1 или оставлю ещё и Q2, то выскакивает трап. 36 ведь не кратно 4... И как это вообще влияет?

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 21:03 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Вот, что я нашёл в интернете, как мне кажется, по этому поводу:
Цитата:
To ensure proper alignment of this values on the stack, the stack boundary must be as aligned as that required by any value stored on the stack. Further, every function must be generated such that it keeps the stack aligned. Thus calling a function compiled with a higher preferred stack boundary from a function compiled with a lower preferred stack boundary will most likely misalign the stack. It is recommended that libraries that use callbacks always use the default setting.

Reading this, I come to the conclusion that in... GCC... nowadays everything is aligned to 16 bytes... That's why my C program linked with SDL2 never crashes, because everything is aligned to 16 bytes, and when the C program is linked with the SDL2 library, the SDL2 library is properly aligned (all of it) to 16 bytes.
http://forum.lazarus.freepascal.org/index.php?topic=29097.0
Если верить этому тексту, можно предположить, что GCC выравнивает длину кадров стэка в процедурах по 16 байтов, а Блэкбокс - нет.
И что теперь делать? Во всех процедурах писать VAR unused: ARRAY [untagged] N OF SHORTCHAR, а N считать вручную?

Автор:  Иван Денисов [ Понедельник, 11 Апрель, 2016 21:11 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Вот из документации поглядите, есть еще другие флаги:
Код:
System flags for record types
Name   Value   Description
untagged   1   No type tag and no type descriptor is allocated.
      The garbage collector ignores untagged variables.
      NEW is not allowed on pointers to untagged variables.
      No type-bound procedures are allowed for the record.
      Pointers to untagged record type or extensions of this
      record type inherit the attribute of being untagged.
      The offsets of the fields are aligned to
      MIN(4-byte, size), where size is the size of the field.
      The size of the record and the offsets of the fields are
      aligned to 32-bit boundaries.
noalign   3   Same as untagged but without alignment.
align2   4   Same as untagged but with
      MIN(2-byte, size) alignment.
align8   6   Same as untagged but with
      MIN(8-byte, size) alignment.
union   7   Untagged record with all fields allocated at offset 0.
      The size of the record is equal to the size of the
      largest field.
      Used to emulate C union types.

Автор:  prospero78 [ Понедельник, 11 Апрель, 2016 21:16 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

В общем, Ваня всё правильно расписал.
Единственно добавлю отсебятину: можно поравнять границы пустыми байтами в структуре.
Я уже тут писал в какой-то из тем, что в Блекбоксе оригинально выравнивание работает. (но логично, и предсказуемо, что ОЧЕНЬ важно).

Автор:  kekc_leader [ Понедельник, 11 Апрель, 2016 21:22 ]
Заголовок сообщения:  Re: NEW для структур без метки (untagged)

Ребята, это я понял.
Но дело в том, что не запись надо выравнивать, а «начало стэка перед вызовом сторонней процедуры». Это самое начало стека должно быть кратно 16-и. Все эти align8 не помогут, т. к. они для записей.
На том форуме пишут, что поблема актуальна только для GCC на Линуксе. Это согласуется с тем, что на Виндоусе этой проблемы действительно нет. GCC'шники решили в какой-то момент на x86 всё выравнивать по 16 байт, а не по 4.
Можно ли где-то в Блэкбоксе поменять какую-нибудь константу, чтоб выравнивание (не записей, а начала стека) работало по 16 байтов? Куда копать?

Страница 2 из 4 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/