-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNotes.txt
162 lines (133 loc) · 10.3 KB
/
Notes.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
--------------- LINUX ----------------------
1. Window Creation
-> XOpenDisplay("machine:display_number.screen_number") to connect to the X server.
-> XVisualInfo demanding a visual of the screen that supports 32bit depth TrueColor display.
-> Window's attributes:Provide a color map that supports the chosen visual.
Side Note: do-not-propogate-mask is the mask of events that should not be sent to the parents of
this window. override-redirect-mask :Configure and Map requests override SubstructureRedirectMask of parent.
TODO(KARAN): I haven't understood these attributes properly but remember they might cause a problem.
-> Create window having the chosen visual and window attributes.
-> Create Graphics Context which is required for operations like blitting and any other "drawing" function
-> Create XImage object that holds reference to an offscreen buffer which is used for rendering. The contents are displayed using XPutImage.
2. Allocation
-> mmap similar to VirtualAlloc
-> munmap to free memory
3. Event Loop
-> XCheckWIndowEvent takes the window and mask of events you are interested in and returns an XEvent object.
-> ConfigureNotify is the type of event that informs us changes to structure of window like resizing, movement,etc.
For this StructureNotifyMask needs to be ORed in the eventsWanted mask.
-> TODO(KARAN): Figure out what the ResizeRedirectMask does(basically check all masks that have "Redirect" in them as they seem to have some different behaviour.
It seems that whenever someone tries to resize the window, it directly lets us handle what to do with the resize if ResizeRedirect is set.
Otherwise it does the default thing.
TODO(KARAN): I haven't understood these redirect masks properly but remember they might cause a problem.
4. Input
-> XQueryPointer allows to directly query the state of mouse at any time.
It returns us the mask of buttons(Button1Mask, Button2Mask, ...) that are currently pressed and X,Y positions of the pointer.
-> XKeysymToKeycode takes a symbolic representation of key and returns its keycode.
For eg: Keysyms XK_A and XK_a will return same keycode.
XQueryKeymap returns 256 long bit mask(char[32]) of keys being pressed.
If "a" is being pressed and its keycode is say 27 then its value will be located in (27/8 = 3rd byte) i.e in char[3]. The bit that represents its state in that byte will be (27 % 8 = 3) i.e. char[3] = xxxxaxxx
5. Timing functions
-> rdtsc implemented using asm
-> clock_gettime: takes a clockid and returns a timespec
-> timespec{tv_sec, tv_nsec} should be interpreted as (tv_sec * 1E9 + tv_nano)ns.
-> clock_nanosleep:can take a absolute time(eg:sleep till 3pm) or relative time(eg:sleep for 1 hour).
6. Compiling 32bit on 64bit machine
-> Installing multiple architecture compilers:
gcc-multilib and g++-multilib
-> Installing 32bit version of -dev packages of libraries you are using.
apt-get install libx11-dev:i386
STACKOVERFLOW ANSWER THAT HELPED:https://askubuntu.com/questions/178592/compiling-32-bit-app-on-64-bit-cannot-find-lx11?newreg=b2cac9b3e5c94b4aadec012056a40726
ANS:You need the header files, which are provided by -dev packages, and not in the library packages themselves. So, try installing libx11-dev. That should fix this particular build error, though you may get similar errors about other libraries (and then you can install their -dev packages.)
Even though these packages provide header files rather than binaries, and in general header files account for all supported architectures through the use of preprocessor macros, nonetheless -dev packages in Ubuntu tend to be architecture-specific, and this is the case for libx11-dev (as can be seen here by expanding a release and finding the .deb packages listed for libx11-dev in that release). Since your Ubuntu system is 64-bit and you're compiling a 32-bit program which must link against the 32-bit version of the library, you'll probably need to install the 32-bit version of libx11-dev. If you're installing with apt-get or aptitude, you can specify that by indicating libx11-dev:i386 as the package to install (since multarch is supported and being used).
http://packages.ubuntu.com/ is a good resource for finding the name of the -dev package corresponding to a library package. It's not always the library package's name immediately followed by -dev; sometimes version numbers present in the library package name, especially after a -, are absent in the name of the corresponding -dev package.
7. ALSA SOUND
-> https://www.tldp.org/HOWTO/Alsa-sound-4.html : To install ALSA drivers.
-> Sources: https://www.alsa-project.org/main/index.php/FramesPeriods
https://www.linuxjournal.com/article/6735?page=0,1#N0x19ab2890.0x19ba78d8
-> Transfering audio buffers of large size can cause high latency.
Hence buffer is divided into periods and transfer is done in units of periods.
Buffer = x periods
Period = y frames
frame = z samples
-> A frame is equivalent of one sample being played, irrespective of the number of channels or the number of bits. e.g.
1 frame of a Stereo 48khz 16bit PCM stream is 4 bytes.
1 frame of a 5.1 48khz 16bit PCM stream is 12 bytes.
A period is the number of frames in between each hardware interrupt. The poll() will return once a period.
The buffer is a ring buffer. The buffer size always has to be greater than one period size.
Commonly this is 2*period size, but some hardware can do 8 periods per buffer.
It is also possible for the buffer size to not be an integer multiple of the period size.
Now, if the hardware has been set to 48000Hz , 2 periods, of 1024 frames each, making a buffer size of 2048 frames.
The hardware will interrupt 2 times per buffer. ALSA will endeavor to keep the buffer as full as possible.
Once the first period of samples has been played, the third period of samples is transfered into the space
the first one occupied while the second period of samples is being played. (normal ring buffer behaviour).
-> General Pseudo Code
open interface for capture or playback
set hardware parameters(access mode, data format, channels, rate, etc.)
while there is data to be processed:
read PCM data (capture)
or write PCM data (playback)
close interface
-> 3 modes of data transfer:
A)Standard I/O (Blocked or non-blocked)
B)Event polling
C)Async callback
-> snd_pcm_avail_delay calls snd_pcm_avail and snd_pcm_delay.
snd_pcm_avail syncs the hardware r/w cursor with the system ring buffer's r/w cursor
Delay is defined as: "For playback the delay is defined as the time that a frame that
is written to the PCM stream shortly after this call will take to be actually audible.
It is as such the overall latency from the write call to the final DAC."
However according to docs, (bufferSizeInSamples - availableSamples) != delaySamples
snd_pcm_avail might include some additional, fixed latencies while snd_pcm_delay does not.
-> Current setup for ALSA
Set buffer duration to 1 second
Set period size to framerate of app (i.e 0.03333ms for 30 fps)
Every frame I try to maintain a fill level of 3 frames worth of samples.(Ideally I would want
to set this to 1 frames worth of samples but that causes frequent underruns).
Thus every frame I write some samples from the start of the buffer to the sound card such
that pending samples + samples wrote = 3 frames worth of samples.
-> SDL seems to push send the entire buffer to ALSA every frame.
8. Deciding on the API structure
There are two ways that come to mind in which the API can be designed:
-> Option 1
Have a `interface.h` which will **forward declare** all the structs, declare all the functions that are required for using the API. Make a `linux_implementation.cpp` and `windows_implementation.cpp` that defines all the structs and implements all the functions that were mentioned in the `interface.h`. Compile `interface.h` and `linux_implementation.cpp` into a lib. Then the client will compile their application as follows:
~~~~~~
g++ platform_independent_application.cpp -llinux_implementation -o app
or
cl platform_independent_application.cpp /link windows_implementation -o app.exe
~~~~~~
-> Advantages
1. User doesn't need to know how the struct is defined.
2. User doesn't need to(can't) allocate the API structs.
-> Disadvantages
1. User doesn't know how the struct is defined.
2. User can't use his own memory allocator to allocate the API structs.
3. Not easy to switch to unity build.
4. Cannot view structs during debugging. (Huge negative for me)
-> Option 2
Have a `linux_interface.h` that will **define** all the structs and declare all the functions that are required for using the API. Make a `linux_implementation.cpp` that implements all the functions declared in the `linux_interface.h`.
Create `platform_independent_application.cpp` that will `#include` the `linux_interface.h` and `linux_implementation.cpp`.
It can then be compiled as follows:
~~~~~~
g++ platform_independent_application.cpp -o app
~~~~~~
or create `platform_independent_application.cpp` that will `#include` the `linux_interface.h`. Compile `linux_interface.h` and `linux_implementation.cpp` into a lib. It can then be compiled as follows:
~~~~~~
g++ platform_independent_application.cpp -llinux_implementation -o app
~~~~~~
Similar process for windows implementation.
-> Advantages
1. User can use the contents of the API structs in the code if they wish to.
2. User can allocate struct using their own memory allocators.
3. Easy switching to Unity build.
4. Can debug structs, routines of the API. (A big plus for me)
-> Disadvantages
1. Can't think of any!
It seems that option 1 makes it less error prone for the user to use the API. However second approach allows the user to tradeoff platform independence by making use of platform specific attributes of an API struct. In my opinion approach two is better mainly because of the debugging benefit.
---------------------------------
Windows accepts 0 to max_uint32(4,294,967,295) bytes to read or write
Linux accepts 0 to max_int32(2,147,483,647) or max_int64(9,223,372,036,854,775,807) bytes to read or write
PF will support max_uint32(4,294,967,295) bytes to read/write (about 4GB)
The file handles on windows can go from -2,147,483,648 to 4,294,967,295
The file handles on linux can go from -2,147,483,648 to 2,147,483,648
PF gives handles in range from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807