GPU PRO 360: Guide to GPGPU 1st Edition Wolfgang
Engel (Editor) download
https://textbookfull.com/product/gpu-pro-360-guide-to-gpgpu-1st-
edition-wolfgang-engel-editor/
Download more ebook from https://textbookfull.com
We believe these products will be a great fit for you. Click
the link to download now, or visit textbookfull.com
to discover even more!
GPU Pro 360 Guide to Geometry Manipulation 1st Edition
Wolfgang Engel
https://textbookfull.com/product/gpu-pro-360-guide-to-geometry-
manipulation-1st-edition-wolfgang-engel/
GPU Pro 360 Guide to Mobile Devices 1st Edition
Wolfgang Engel
https://textbookfull.com/product/gpu-pro-360-guide-to-mobile-
devices-1st-edition-wolfgang-engel/
GPU Pro 360 Guide to Image Space 1st Edition Wolfgang
Engel (Author)
https://textbookfull.com/product/gpu-pro-360-guide-to-image-
space-1st-edition-wolfgang-engel-author/
GPU Pro 360 Guide to 3D Engine Design 1st Edition
Wolfgang Engel (Author)
https://textbookfull.com/product/gpu-pro-360-guide-to-3d-engine-
design-1st-edition-wolfgang-engel-author/
GPU Zen Advanced Rendering Techniques Wolfgang Engel
(Editor)
https://textbookfull.com/product/gpu-zen-advanced-rendering-
techniques-wolfgang-engel-editor/
Game AI Pro 360: Guide to Architecture 1st Edition
Steve Rabin (Author)
https://textbookfull.com/product/game-ai-pro-360-guide-to-
architecture-1st-edition-steve-rabin-author/
Game AI Pro 360: Guide to Character Behavior 1st
Edition Steve Rabin (Author)
https://textbookfull.com/product/game-ai-pro-360-guide-to-
character-behavior-1st-edition-steve-rabin-author/
Game AI Pro 360: Guide to Movement and Pathfinding 1st
Edition Steve Rabin (Author)
https://textbookfull.com/product/game-ai-pro-360-guide-to-
movement-and-pathfinding-1st-edition-steve-rabin-author/
Game AI Pro 360: Guide to Tactics and Strategy 1st
Edition Steve Rabin (Author)
https://textbookfull.com/product/game-ai-pro-360-guide-to-
tactics-and-strategy-1st-edition-steve-rabin-author/
GPU Pro 360
Guide to GPGPU
GPU Pro 360
Guide to GPGPU
Edited by Wolfgang Engel
CRC Press
Taylor & Francis Group
6000 Broken Sound Parkway NW, Suite 300
Boca Raton, FL 33487-2742
c 2019 by Taylor & Francis Group, LLC
CRC Press is an imprint of Taylor & Francis Group, an Informa business
No claim to original U.S. Government works
Printed on acid-free paper
International Standard Book Number-13: 978-1-138-48439-9 (Paperback)
International Standard Book Number-13: 978-1-138-48441-2 (Hardback)
This book contains information obtained from authentic and highly regarded sources. Reasonable efforts have
been made to publish reliable data and information, but the author and publisher cannot assume responsibility
for the validity of all materials or the consequences of their use. The authors and publishers have attempted to
trace the copyright holders of all material reproduced in this publication and apologize to copyright holders if
permission to publish in this form has not been obtained. If any copyright material has not been acknowledged
please write and let us know so we may rectify in any future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced, transmitted,
or utilized in any form by any electronic, mechanical, or other means, now known or hereafter invented,
including photocopying, microfilming, and recording, or in any information storage or retrieval system, without
written permission from the publishers.
For permission to photocopy or use material electronically from this work, please access www.copyright.com
(http://www.copyright.com/) or contact the Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive,
Danvers, MA 01923, 978-750-8400. CCC is a not-for-profit organization that provides licenses and registration
for a variety of users. For organizations that have been granted a photocopy license by the CCC, a separate
system of payment has been arranged.
Trademark Notice: Product or corporate names may be trademarks or registered trademarks, and are used
only for identification and explanation without intent to infringe.
Library of Congress Cataloging-in-Publication Data
Names: Engel, Wolfgang F., editor.
Title: GPU pro 360 guide to GPGPU / [edited by] Wolfgang Engel.
Description: First edition. | Boca Raton, FL : CRC Press/Taylor & Francis Group, 2018. | Includes
bibliographical references and index.
Identifiers: LCCN 2018020469| ISBN 9781138484399 (pbk. : acid-free paper) |
ISBN 9781138484412 (hardback : acid-free paper)
Subjects: LCSH: Computer graphics. | Graphics processing units--Programming.
Classification: LCC T385 .G68878 2018 | DDC 006.6--dc23
LC record available at https://lccn.loc.gov/2018020469
Visit the eResources: www.crcpress.com/9781138484399
Visit the Taylor & Francis Web site at
http://www.taylorandfrancis.com
and the CRC Press Web site at
http://www.crcpress.com
Contents
Introduction xi
Web Materials xv
1 2D Distance Field Generation with the GPU 1
Philip Rideout
1.1 Vocabulary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Manhattan Grassfire . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Horizontal-Vertical Erosion . . . . . . . . . . . . . . . . . . . . 6
1.4 Saito-Toriwaki Scanning with OpenCL . . . . . . . . . . . . . 8
1.5 Signed Distance with Two Color Channels . . . . . . . . . . . 16
1.6 Distance Field Applications . . . . . . . . . . . . . . . . . . . 18
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2 Order-Independent Transparency Using Per-Pixel Linked Lists 23
Nicolas Thibieroz
2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.2 Algorithm Overview . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3 DirectX 11 Features Requisites . . . . . . . . . . . . . . . . . 24
2.4 Head Pointer and Nodes Buffers . . . . . . . . . . . . . . . . . 25
2.5 Per-Pixel Linked List Creation . . . . . . . . . . . . . . . . . . 27
2.6 Per-Pixel Linked Lists Traversal . . . . . . . . . . . . . . . . . 30
2.7 Multisampling Antialiasing Support . . . . . . . . . . . . . . . 35
2.8 Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.9 Tiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.10 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.11 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 45
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3 Simple and Fast Fluids 47
Martin Guay, Fabrice Colin, and Richard Egli
3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
v
vi Contents
3.2 Fluid Modeling . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.3 Solver’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . 50
3.4 Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.5 Visualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.6 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4 A Fast Poisson Solver for OpenCL Using Multigrid Methods 59
Sebastien Noury, Samuel Boivin, and Olivier Le Maı̂tre
4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.2 Poisson Equation and Finite Volume Method . . . . . . . . . . 60
4.3 Iterative Methods . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.4 Multigrid Methods (MG) . . . . . . . . . . . . . . . . . . . . . 71
4.5 OpenCL Implementation . . . . . . . . . . . . . . . . . . . . . 74
4.6 Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.7 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5 Volumetric Transparency with Per-Pixel Fragment Lists 87
László Szécsi, Pál Barta, and Balázs Kovács
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.2 Light Transport Model . . . . . . . . . . . . . . . . . . . . . . 88
5.3 Ray Decomposition . . . . . . . . . . . . . . . . . . . . . . . . 89
5.4 Finding Intersections with Ray Casting . . . . . . . . . . . . . 91
5.5 Application for Particle System Rendering . . . . . . . . . . . 94
5.6 Finding Intersections with Rasterization . . . . . . . . . . . . 95
5.7 Adding Surface Reflection . . . . . . . . . . . . . . . . . . . . 97
5.8 Shadow Volumes . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.9 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
6 Practical Binary Surface and Solid Voxelization with Direct3D 11 101
Michael Schwarz
6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.2 Rasterization-Based Surface Voxelization . . . . . . . . . . . . 102
6.3 Rasterization-Based Solid Voxelization . . . . . . . . . . . . . 106
6.4 Conservative Surface Voxelization with DirectCompute . . . . 108
6.5 Solid Voxelization with DirectCompute . . . . . . . . . . . . . 113
6.6 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Contents vii
7 Interactive Ray Tracing Using the Compute Shader in DirectX 11 117
Arturo Garcı́a, Francisco Ávila, Sergio Murguı́a, and Leo Reyes
7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
7.2 Ray Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
7.3 Our Implementation . . . . . . . . . . . . . . . . . . . . . . . 121
7.4 Primary Rays Stage . . . . . . . . . . . . . . . . . . . . . . . . 125
7.5 Intersection Stage . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.6 Color Stage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7.7 Multipass Approach . . . . . . . . . . . . . . . . . . . . . . . . 135
7.8 Results and Discussion . . . . . . . . . . . . . . . . . . . . . . 135
7.9 Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
7.10 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
7.11 Further Work . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
7.12 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 139
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
8 Bit-Trail Traversal for Stackless LBVH on DirectCompute 141
Sergio Murguı́a, Francisco Ávila, Leo Reyes, and Arturo Garcı́a
8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
8.2 Ray Tracing Rendering . . . . . . . . . . . . . . . . . . . . . . 142
8.3 Global Illumination . . . . . . . . . . . . . . . . . . . . . . . . 142
8.4 Stackless LBVH . . . . . . . . . . . . . . . . . . . . . . . . . . 144
8.5 The SLBVH in Action . . . . . . . . . . . . . . . . . . . . . . 153
8.6 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
8.7 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 157
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
9 Real-Time JPEG Compression Using DirectCompute 159
Stefan Petersson
9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
9.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . 164
9.3 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
9.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
9.5 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 177
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
10 Hair Simulation in TressFX 179
Dongsoo Han
10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
10.2 Simulation Overview . . . . . . . . . . . . . . . . . . . . . . . 180
10.3 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
10.4 Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
viii Contents
10.5 Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
10.6 Wind and Collision . . . . . . . . . . . . . . . . . . . . . . . . 184
10.7 Authoring Hair Asset . . . . . . . . . . . . . . . . . . . . . . . 185
10.8 GPU Implementation . . . . . . . . . . . . . . . . . . . . . . . 186
10.9 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
11 Object-Order Ray Tracing for Fully Dynamic Scenes 191
Tobias Zirr, Hauke Rehfeld, and Carsten Dachsbacher
11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
11.2 Object-Order Ray Tracing Using the Ray Grid . . . . . . . . . 193
11.3 Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
11.4 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . 196
11.5 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
11.6 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
12 Quadtrees on the GPU 211
Jonathan Dupuy, Jean-Claude Iehl, and Pierre Poulin
12.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
12.2 Linear Quadtrees . . . . . . . . . . . . . . . . . . . . . . . . . 212
12.3 Scalable Grids on the GPU . . . . . . . . . . . . . . . . . . . . 215
12.4 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
12.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
13 Two-Level Constraint Solver and Pipelined Local Batching for Rigid
Body Simulation on GPUs 223
Takahiro Harada
13.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
13.2 Rigid Body Simulation . . . . . . . . . . . . . . . . . . . . . . 224
13.3 Two-Level Constraint Solver . . . . . . . . . . . . . . . . . . . 226
13.4 GPU Implementation . . . . . . . . . . . . . . . . . . . . . . . 228
13.5 Comparison of Batching Methods . . . . . . . . . . . . . . . . 231
13.6 Results and Discussion . . . . . . . . . . . . . . . . . . . . . . 233
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
14 Non-separable 2D, 3D, and 4D Filtering with CUDA 241
Anders Eklund and Paul Dufort
14.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
14.2 Non-separable Filters . . . . . . . . . . . . . . . . . . . . . . . 243
14.3 Convolution vs. FFT . . . . . . . . . . . . . . . . . . . . . . . 246
14.4 Previous Work . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
Contents ix
14.5 Non-separable 2D Convolution . . . . . . . . . . . . . . . . . . 247
14.6 Non-separable 3D Convolution . . . . . . . . . . . . . . . . . . 252
14.7 Non-separable 4D Convolution . . . . . . . . . . . . . . . . . . 253
14.8 Non-separable 3D Convolution, Revisited . . . . . . . . . . . . 254
14.9 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
14.10 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
15 Compute-Based Tiled Culling 265
Jason Stewart
15.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
15.2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
15.3 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . 267
15.4 Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
15.5 Unreal Engine 4 Results . . . . . . . . . . . . . . . . . . . . . 282
15.6 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
15.7 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 288
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
16 Rendering Vector Displacement-Mapped Surfaces in a GPU Ray
Tracer 289
Takahiro Harada
16.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
16.2 Displacement Mapping . . . . . . . . . . . . . . . . . . . . . . 289
16.3 Ray Tracing a Scene with Vector Displacement Maps . . . . . 291
16.4 Ray Tracing a Vector Displacement Patch . . . . . . . . . . . 291
16.5 Integration into an OpenCL Ray Tracer . . . . . . . . . . . . 297
16.6 Results and Discussion . . . . . . . . . . . . . . . . . . . . . . 300
16.7 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
17 Smooth Probabilistic Ambient Occlusion for Volume Rendering 305
Thomas Kroes, Dirk Schut, and Elmar Eisemann
17.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
17.2 Smooth Probabilistic Ambient Occlusion . . . . . . . . . . . . 306
17.3 Approximating Ambient Occlusion . . . . . . . . . . . . . . . 311
17.4 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
17.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
x Contents
18 Octree Mapping from a Depth Camera 317
Dave Kotfis and Patrick Cozzi
18.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
18.2 Previous Work and Limitations . . . . . . . . . . . . . . . . . 320
18.3 Octree Scene Representation . . . . . . . . . . . . . . . . . . . 321
18.4 Rendering Techniques . . . . . . . . . . . . . . . . . . . . . . . 327
18.5 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
18.6 Conclusion and Future Work . . . . . . . . . . . . . . . . . . . 331
18.7 Acknowledgment . . . . . . . . . . . . . . . . . . . . . . . . . 332
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
19 Interactive Sparse Eulerian Fluid 335
Alex Dunn
19.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
19.2 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
19.3 GPU Eulerian Fluid Simulation . . . . . . . . . . . . . . . . . 336
19.4 Simulation Stages . . . . . . . . . . . . . . . . . . . . . . . . . 337
19.5 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
19.6 Latency Resistant Sparse Fluid Simulation . . . . . . . . . . . 350
19.7 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
19.8 Sparse Volume Rendering . . . . . . . . . . . . . . . . . . . . . 353
19.9 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
19.10 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
About the Contributors 359
Introduction
Today, the use of GPGPU is prevalent in most modern architectures. With the
parallel nature of the GPU, any algorithm that can process data in parallel can
generally run orders of magnitudes faster than their CPU counterparts. Therefore
it makes sense to take advantage of this power, considering that suitable hardware
can now be found on most common hardware configurations. This book will cover
chapters that present techniques that go beyond the normal pixel and triangle
scope of GPUs and take advantage of the parallelism of modern graphic processors
to accomplish such tasks.
In the first chapter, “2D Distance Field Generation with the GPU,” Philip
Rideout presents a simple and effective technique to generate distance fields from
an image using the OpenCL API. Distance fields have many applications in image
processing, real-time rendering, and path-finding algorithms. A distance field is
a grayscale bitmap in which each pixel’s intensity represents the distance to the
nearest contour line in a source image. Rideout explains how such distance fields
can be efficiently generated on the GPU and also provides a few examples of how
the resulting distance fields can be used in practical applications.
In the next chapter, “Order-Independent Transparency Using Per-Pixel Linked
Lists” by Nicolas Thibieroz, a technique is presented that takes advantage of un-
ordered access views to generate a dynamic link list, which can in turn be used
to render order-independent translucency. By storing translucent pixels in such a
list, they can be sorted as an after process and therefore properly render translu-
cencies regardless of their order.
The third chapter, “Simple and Fast Fluids” by Martin Guay, Fabrice Colin,
and Richard Egli, presents a new algorithm that can be used to solve fluid sim-
ulations efficiently using compute APIs on the GPU. The chapter details how
the fluid solver works, discusses boundary conditions for single phase flows, and
provides a few examples of how such solvers can be used in practical scenarios.
In “A Fast Poisson Solver for OpenCL Using Multigrid Methods” by Sebastien
Noury, Samuel Boivin, and Olivier Le Maı̂tre, a novel technique is presented to
allow the solving of Poisson partial differential equations using OpenCL. The
resolution of Poisson partial differential equations is often needed to solve many
techniques in computer graphics, such as fluid dynamics or the merging and
deformation of complex meshes. This chapter focuses on the presentation of an
xi
xii Introduction
algorithm that allows for the efficient implementation of a Poisson solver using
the GPU.
“Volumetric Transparency with Per-Pixel Fragment Lists” by László Szécsi,
Pál Barta, and Balázs Kovács, presents an efficient approach to rendering mul-
tiple layers of translucency by harnessing the power of compute shaders. By
implementing a simple ray-tracing approach in a computational shader, they can
determine the appropriate color intensity for simple particles. The approach can
then be taken further and extended to even account for visual effects such as
refraction and volumetric shadows.
In the next chapter, “Practical Binary Surface and Solid Voxelization with
Direct3D 11” by Michael Schwarz, a new real-time voxelization technique is
presented. This technique is efficient and tackles some of the problems, such
as voxel holes, that occur in rasterization-based voxelization algorithms. The
resulting voxels can then be used in the application of a variety of techniques
such as collision detection, ambient occlusion, and even real-time global
illumination.
In “Interactive Ray Tracing Using the Compute Shader in DirectX 11” by
Arturo Garcı́a, Francisco Ávila, Sergio Murguı́a, and Leo Reyes, a novel technique
is presented to allow for real-time interactive ray tracing using a combination of
the GPU and CPU processing power. This implementation properly handles
glossy reflections as global illumination. An efficient bounding volume hierarchy
is also offered to accelerate the discovery of ray intersections.
“Bit-Trail Traversal for Stackless LBVH on DirectCompute,” by Sergio Mur-
guı́a, Francisco Àvila, Leo Reyes, and Arturo Garcı́a, describes an improvement
to existing stackless bounding volume hierarchy (BVH) methods that enables
the fast construction of the structure while maintaining traversal performance
sufficient for real-time ray tracing. The algorithm can be used for basic ray tracing
but can also be extended for use in global illumination and other algorithms
that can depend on rapid BVH traversal on the GPU. The chapter covers an
implementation of the stackless linear BVH running solely on the GPU as well
as the various traversal algorithms that may be needed.
In “Real-Time JPEG Compression Using DirectCompute,” Stefan Petersson
describes a complete JPEG encoder implementation on the GPU using Direct-
Compute. This allows for the real-time storage and encoding of not only image
data but also video sequences. With the close integration of the encoder with the
application, the latency and compression cost is reduced, making real-time video
streaming from 3D applications more feasible. In the chapter, he covers all as-
pects from color quantization to color-space conversions and entropy coding—and
how each of the different elements can be implemented on the GPU.
The chapter by Dongsoo Han, “Hair Simulation in TressFX,” describes the
simulation algorithms used in the game Tomb Raider to animate Lara Croft’s
hair and in the AMD demo Ruby. TressFX can simulate 19,000 strands of hair,
consisting of 0.22 million vertices in less than a millisecond on a high-end GPU.
Introduction xiii
The next chapter, “Object-Order Ray Tracing for Fully Dynamic Scenes”
by Tobias Zirr, Hauke Rehfeld, and Carsten Dachsbacher, describes the imple-
mentation of a ray tracer that is capable of utilizing the same art assets as a
rasterizer-based engine, which is one of the major obstacles in using ray tracers
in games.
The chapter “Quadtrees on the GPU” by Jonathan Dupuy, Jean-Claude Iehl,
and Pierre Poulin describes a quadtree implementation that is implemented with
linear trees on the GPU. The chapter explains how to update linear trees, which
are a pointer-free alternative to recursive trees on the GPU, and how to render
multiresolution, crack-free surfaces with frustum culling using hardware tessella-
tion and a distance-based LOD selection criterion.
A key feature for simulating rigid bodies on the GPU is the performance of the
constraint solver. Takahiro Harada shows in his chapter “Two-Level Constraint
Solver and Pipelined Local Batching for Rigid Body Simulation on GPUs” an
implementation that uses pipelined batching to run the entire solver on the GPU.
This constraint solver is also implemented in the Bullet Physics Engine.
The next chapter, “Non-separable 2D, 3D, and 4D Filtering with CUDA” by
Anders Eklund and Paul Dufort, covers the efficient implementation of filtering
algorithms tailored to deal with 3D and 4D datasets, which commonly occur in
medical imaging, and 2D datasets.
“Compute-Based Tiled Culling,” Jason Stewart’s chapter, focuses on one chal-
lenge in modern real-time rendering engines: they need to support many dynamic
light sources in a scene. Both forward and deferred rendering can struggle with
problems such as efficient culling, batch sizes, state switching, or bandwidth con-
sumption, in this case. Compute-based (tiled) culling of lights reduces state
switching and avoids culling on the CPU (beneficial for forward rendering), and
computes lighting in a single pass that fits deferred renderers well. Stewart details
his technique, provides a thorough performance analysis, and deduces various op-
timizations, all documented with example code.
In “Rendering Vector Displacement-Mapped Surfaces in a GPU Ray Tracer,”
Takahiro Harada’s work targets the rendering of vector displacement-mapped
surfaces using ray-tracing–based methods. Vector displacement is a popular and
powerful means to model complex objects from simple base geometry. However,
ray tracing such geometry on a GPU is nontrivial: pre-tessellation is not an option
due to the high (and possibly unnecessary) memory consumption, and thus effi-
cient, GPU-friendly algorithms for the construction and traversal of acceleration
structures and intersection computation with on-the-fly tessellation are required.
Harada fills this gap and presents his method and implementation of an OpenCL
ray tracer supporting dynamic tessellation of vector displacement-mapped sur-
faces.
“Smooth Probablistic Ambient Occlusion for Volume Rendering” by Thomas
Kroes, Dirk Schut, and Elmar Eisemann covers a novel and easy-to-implement
solution for ambient occlusion for direct volume rendering (DVR). Instead of ap-
xiv Introduction
plying costly ray casting to determine the accessibility of a voxel, this technique
employs a probabilistic heuristic in concert with 3D image filtering. This way,
ambient occlusion can be efficiently approximated and it is possible to interac-
tively modify the transfer function, which is critical in many applications, such
as medical and scientific DVR.
The chapter, “Octree Mapping from a Depth Camera,” shows how to render
artificial objects with consistent shading from arbitrary perspectives in a real-
world scene. This chapter uses CUDA to reconstruct 3D scenes from depth
cameras at near real-time speeds. The scene is represented by a sparse voxel
octree (SVO) structure that scales to large volumes.
The last chapter, “Interactive Sparse Eulerian Fluid,” describes a method
for computing and rendering smoke-like fluid in real time on the GPU using
DirectX 11+ with a key focus on the advantages of simulating and storing these
simulations in a sparse domain. This technique was used with impressive results
in the NVIDIA Mech Ti demo.
Web Materials
Example programs and source code to accompany some of the chapters are avail-
able on the CRC Press website: go to https://www.crcpress.com/9781138484399
and click on the “Downloads” tab.
The directory structure follows the book structure by using the chapter num-
bers as the name of the subdirectory.
General System Requirements
The material presented in this book was originally published between 2010 and
2016, and the most recent developments have the following system requirements:
• The DirectX June 2010 SDK (the latest SDK is installed with Visual Studio
2012).
• DirectX 11 or DirectX 12 capable GPUs are required to run the examples.
The chapter will mention the exact requirement.
• The OS should be Microsoft Windows 10, following the requirement of
DirectX 11 or 12 capable GPUs.
• Visual Studio C++ 2012 (some examples might require older versions).
• 2GB RAM or more.
• The latest GPU driver.
xv
1
2D Distance Field Generation
with the GPU
Philip Rideout
Distance fields have many applications in image processing, real-time rendering,
and path-finding algorithms. Loosely speaking, a distance field is a grayscale
bitmap in which each pixel’s intensity represents the distance to the nearest
contour line in a source image (see Figure 1.1). The source image often consists
of monochrome vector art or text. Distance fields can also be defined in higher
dimensions—in the 3D case, the value at each voxel represents distance to the
nearest surface. When extended to 3D, many more applications come into play,
including facilitation of ray casting and collision detection.
In this chapter we focus on the 2D case. The flat world is much less daunting
than 3D, and serves as a good starting point for learning about distance fields.
We will focus on the generation of distance fields rather than their application,
but will conclude with a brief overview of some rendering techniques that leverage
distance fields, including one that enables cheap, high-quality antialiasing.
Perhaps the most classic and commonly-used technique for generating distance
fields stems from Per-Erik Danielsson [Danielsson 80]. He describes a method by
which pairs of distances are “swept” through an image using a small grid of
Figure 1.1. Fleur-de-lis seed image (left) and its resulting distance field (right).
1
2 1. 2D Distance Field Generation with the GPU
weights (which he calls a skeleton). Danielsson’s method is ingenious and much
faster than a brute-force technique; however, his algorithm cannot be conveyed
succinctly, and is difficult to parallelize on present-day GPU architectures.
Some fascinating and efficient methods for 2D distance field generation on the
GPU have been proposed recently [Cao et al. 10] but many of these methods are
complex, requiring cunning tricks such as embedding doubly-linked lists within a
texture. Here, we give an overview of techniques that are GPU-amenable while
still being relatively easy to follow, starting with the simplest (and least accurate)
method, which we’re calling Manhattan grassfire. Although intuitive and easy to
implement with OpenGL, this algorithm does not produce accurate results.
After reviewing Manhattan grassfire, we’ll introduce a new, more accurate,
technique called horizontal-vertical erosion, which is also easy to implement using
OpenGL. Finally, we’ll cover an efficient algorithm proposed by Saito-Toriwaki
[Saito and Toriwaki 94]. The nature of their algorithm is amenable to the GPU
only when using a compute API rather than a graphics-oriented API. We’ll show
how we implemented their method using OpenCL.
1.1 Vocabulary
In the context of distance fields, the definition of distance (also known as the
metric) need not be “distance” in the physical sense that we’re all accustomed to.
• Euclidean metric. This is the classic definition of distance and corresponds
to the physical world.
• Manhattan metric. The sum of the axis-aligned horizontal and vertical
distances between two points. As Pythagoras taught us, city block distance
is not equivalent to Euclidean distance. However, it tends to be much easier
to compute.
• Chessboard metric. Rather than summing the horizontal and vertical dis-
tances, take their maximum. This is the minimum number of moves a king
needs when traveling between two points on a chessboard. Much like the
Manhattan metric, chessboard distance tends to be easier to compute than
true Euclidean distance.
• Squared Euclidean metric. This is a distance field where each value is
squared distance rather than true distance. This is good enough for many
applications, and easier to compute. It also serves as a convenient interme-
diary step when computing true Euclidean distance.
• Seed image. Ordinarily this isn’t thought of as a distance metric; it’s a
binary classification consisting of object pixels and background pixels. In
this chapter, object pixels are depicted in black and background pixels
are white.
1.1. Vocabulary 3
Figure 1.2. Seed image (left), Manhattan distance (middle), Euclidean distance (right).
See Figure 1.2 for an example of a seed image and a comparison of Manhattan
and Euclidean metrics.
It also helps to classify the generation algorithms that are amenable to the
GPU:
• Grassfire. These types of algorithms incrementally flood the boundaries of
the vector art outward, increasing the distance values along the way. Once a
pixel has been set, it never changes. The algorithm’s termination condition
is that all background pixels have been set.
• Erosion. Much like grassfire methods, erosion algorithms iteratively manip-
ulate the entire image. Unlike grassfire, pixel values are constantly read-
justing until an equilibrium state has been reached.
• Scanning. Instead of generating a succession of new images, scanning meth-
ods “sweep” through the seed image, propagating values horizontally or
vertically. Scanning techniques are less amenable to OpenGL, but are often
parallelizable using OpenCL or CUDA.
• Voronoi. Distance fields are closely related to Voronoi maps, which are
classically generated on the GPU by drawing z-aligned cones into the depth
buffer. Alternatively, cone tessellation can be avoided by splatting soft
particles with a blending equation of min(source, dest). Voronoi-based
techniques tend to be raster-heavy, and are more amenable to source images
that contain clouds of discrete points (much like Figure 1.2) rather than
source images that have continuous outlines (like the Fleur-de-Lis shape).
Jump flooding is an interesting Voronoi-based technique presented in [Rong
and Tan 06].
Grassfire and erosion techniques are typically implemented with a graphics
API using an image-processing technique called ping-ponging. The fragment
shader cannot read values back from the render target, so two image surfaces are
4 1. 2D Distance Field Generation with the GPU
created: surface A and surface B. On even-numbered passes, surface A is used
as a source texture and surface B is used as the render target. On odd-numbered
passes, surface B is the source texture and surface A is the render target.
1.2 Manhattan Grassfire
The following diagram illustrates a well-known method for computing the Man-
hattan metric using a 4 bits-per-pixel surface. The left-most image is the seed
image, and the right-most image contains the final distance field. Blue cells repre-
sent background pixels and contain a value of 0xF. Note that the last two images
are identical; the last pass is intentionally redundant to allow an occlusion query
to signal termination (more on this later).
Tex A Tex B Tex A Tex B Tex A Tex B
F F F F F F F F F F F F 2 F F F 3 2 3 F 4 3 2 3 4 4 3 2 3 4
F F F F F F F 1 F F F 2 1 2 F 3 2 1 2 3 3 2 1 2 3 3 2 1 2 3
F F 0 F F F 1 0 1 F 2 1 0 1 2 2 1 0 1 2 2 1 0 1 2 2 1 0 1 2
F F 0 F F F 1 0 1 F 2 1 0 1 2 2 1 0 1 2 2 1 0 1 2 2 1 0 1 2
F F F F F F F 1 F F F 2 1 2 F 3 2 1 2 3 3 2 1 2 3 3 2 1 2 3
F F F F F F F F F F F F 2 F F F 3 2 3 F 4 3 2 3 4 4 3 2 3 4
The fragment shader (for OpenGL 3.0 and above) used in each rendering pass
is shown in Listing 1.1. This shader assumes that the render target and source
texture have formats that are single-component, 8-bit unsigned integers.
out uint FragColor ;
uniform usampler2D Sampler ;
void main ()
{
ivec2 coord = ivec2 ( gl_FragCoord . xy );
uint color = texelFetch ( Sampler , coord ,0). r ;
if ( color != 255 u )
discard ;
uint n = tex e l F e t c h Of f s e t ( Sampler , coord ,0 , ivec2 (0 , -1)). r ;
uint s = tex e l F e t c h Of f s e t ( Sampler , coord ,0 , ivec2 (0 ,+1)). r ;
uint e = tex e l F e t c h Of f s e t ( Sampler , coord ,0 , ivec2 (+1 ,0)). r ;
uint w = tex e l F e t c h Of f s e t ( Sampler , coord ,0 , ivec2 ( -1 ,0)). r ;
FragColor = min (n , min (s , min (e , w )));
if ( FragColor < 254 u )
FragColor ++;
}
Listing 1.1. Grassfire fragment shader.
1.2. Manhattan Grassfire 5
To summarize the shader: if the current pixel is not a background pixel, it
can be skipped because it has already been filled. Otherwise, find the minimum
value from the neighboring pixels in the four cardinal directions (n, s, e, w). To
enhance this shader to compute a chessboard metric, simply add four new texture
lookups for the diagonal neighbors (ne, nw, se, sw).
The grassfire algorithm is easy to implement, but it’s not obvious how to
detect when a sufficient number of passes has been completed. In the worst case,
the number of passes is max(width, height). In practice, the number of passes
is much fewer.
The occlusion query capabilities in modern graphics hardware can help. In
Listing 1.1, we issue a discard statement for non-background pixels. You might
wonder why we didn’t do this instead:
if ( color != 255 u ) {
FragColor = color ;
return ;
}
Using discard instead of return is crucial; it allows us to leverage an oc-
clusion query to terminate the image processing loop. If all pixels are discarded,
then no change occurs, and the algorithm is complete.
One consequence of using discard in this way is that some pixels in destina-
tion surface are left uninitialized. To fix this, we need to blit the entire source
texture before running the erosion shader. Luckily this is a fast operation on
modern GPUs. See Listing 1.2 for the complete image processing loop.
bool done = false ;
int pass = 0;
while (! done ) {
// Swap the source & destination surfaces and bind them
Swap ( Source , Dest );
gl Bin dFr ameb uff er ( GL_FRAMEBUFFER , Dest . RenderTarget );
glBindTexture ( GL_TEXTURE_2D , Source . TextureHandle );
// Copy the entire source image to the target
glUseProgram ( BlitProgram );
glDrawArrays ( GL_TRIANGLE_FAN ,0 ,4);
// Execute the grassfire shader and measure the pixel count
glUseProgram ( GrassfirePro g r a m );
glBeginQuery ( GL_SAMPLES_PASSED , QueryObject );
glDrawArrays ( GL_TRIANGLE_FAN ,0 ,4);
glEndQuery ( GL _SA MPL ES_ PAS S E D );
// If all pixels were discarded , we ’ re done
GLuint count = 0;
6 1. 2D Distance Field Generation with the GPU
g l G e t Qu e r y O b j e c t u i v ( QueryObject , GL_QUERY_RESULT ,& count );
done = ( count == 0) || ( pass ++ > MaxPassCount );
}
Listing 1.2. C algorithm for Manhattan grassfire.
Note that Listing 1.2 also checks against the MaxPassCount constant for loop
termination. This protects against an infinite loop in case an error occurs in the
fragment shader or occlusion query.
1.3 Horizontal-Vertical Erosion
Although intuitive, the method presented in the previous section is only marginally
useful, because it computes distance according to a city block metric. In this sec-
tion, we present a new technique that generates distance according to a squared
Euclidean metric. The algorithm consists of two separate image-processing loops.
The first loop makes a succession of horizontal transformations and the second
loop makes a succession of vertical transformations. At each pass, an odd in-
teger offset is applied to the propagated distance values (β in Figures 1.3 and
1.4, which illustrate the process on a 4-bit surface). This is similar to a parallel
method proposed by [Lotufo and Zampirolli 01].
Tex A, d=0 Tex B, d=1, β=1 Tex A, d=2, β=3 Tex B, d=3, β=5 Tex A, d=4, β=7
F F F F F F F F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F F F F F F F F
F F 0 F F F 1 0 1 F 4 1 0 1 4 4 1 0 1 4 4 1 0 1 4
F F 0 F F F 1 0 1 F 4 1 0 1 4 4 1 0 1 4 4 1 0 1 4
F F F F F F F F F F F F F F F F F F F F F F F F F
F F F 0 F F F 1 0 1 F 4 1 0 1 9 4 1 0 1 9 4 1 0 1
Figure 1.3. Horizontal erosion.
F F F 0 F F F 1 0 1 F 4 1 0 1 9 4 1 0 1 9 4 1 0 1
Tex A, d=0 Tex B, d=1, β=1 Tex A, d=2, β=3 Tex B, d=3, β=5
F F F F F F F F F F 8 5 4 5 8 8 5 4 5 8
F F F F F 5 2 1 2 5 5 2 1 2 5 5 2 1 2 5
4 1 0 1 4 4 1 0 1 4 4 1 0 1 4 4 1 0 1 4
4 1 0 1 4 4 1 0 1 4 4 1 0 1 4 4 1 0 1 4
F F F F F 5 2 1 1 2 5 2 1 1 2 5 2 1 1 2
9 4 1 0 1 9 4 1 0 1 8 4 1 0 1 8 4 1 0 1
Figure 1.4. Vertical erosion.
1.3. Horizontal-Vertical Erosion 7
You might be wondering why this is erosion rather than grassfire, according
to our terminology. In Figure 1.4, notice that a 9 changes into an 8 during the
second pass. Since a nonbackground pixel changes its value, this is an erosion-
based method.
The fragment shader for the horizontal stage of processing is shown next.
out uint FragColor ;
uniform usampler2D Sampler ;
uniform uint Beta ;
uniform uint MaxDistance ;
void main ()
{
ivec2 coord = ivec2 ( gl_FragCoord . xy );
uint A = texelFetch ( Sampler , coord ,0). r ;
uint e = texelFetchOffset ( Sampler , coord ,0 , ivec2 (+1 ,0)). r ;
uint w = texelFetchOffset ( Sampler , coord ,0 , ivec2 ( -1 ,0)). r ;
uint B = min ( min (A , e + Beta ) , w + Beta );
if ( A == B || B > MaxDistance )
discard ;
FragColor = B ;
}
Listing 1.3. Erosion fragment shader.
Background pixels are initially set to “infinity,” (i.e., the largest possible value
allowed by the bit depth). Since the shader discards pixels greater than the
application-defined MaxDistance constant, it effectively clamps the distance val-
ues. We’ll discuss the implications of clamping later in this chapter.
To create the shader for the vertical pass, simply replace the two East-West
offsets (+1,0) and (-1,0) in Listing 1.3 with North-South offsets (0,+1) and (0,-1).
To give the erosion shaders some context, the C code is shown next.
GLuint program = Hor izo nta lPr o g r a m ;
for ( int d = 1; d < MaxPassCount ; d ++) {
// Swap the source & destination surfaces and bind them
Swap ( Source , Dest );
gl Bin dFr ameb uff er ( GL_FRAMEBUFFER , Dest . RenderTarget );
glBindTexture ( GL_TEXTURE_2D , Source . TextureHandle );
// Copy the entire source image to the destination surface
glUseProgram ( BlitProgram );
8 1. 2D Distance Field Generation with the GPU
glDrawArrays ( GL_TRIANGLE_FAN ,0 ,4);
// Execute the erosion shader and measure the pixel count
glUseProgram ( program );
glUniform1ui ( Uniforms . Beta , 2* d -1);
glUniform1ui ( Uniforms . MaxDistance , 65535);
glBeginQuery ( GL_SAMPLES_PASSED , QueryObject );
glDrawArrays ( GL_TRIANGLE_FAN ,0 ,4);
glEndQuery ( G L _ S A M P L E S _ P A S S E D );
// If all pixels were discarded , we ’ re done with this stage
GLuint count = 0;
g l G e t Qu e r y O b j e c t u i v ( QueryObject , GL_QUERY_RESULT ,& count );
if ( count == 0) {
if ( program == H o r i z o n t a l P r o g r a m ) {
program = V e rt ic al P ro gr am ;
d = 0;
} else {
break ;
}
}
}
Listing 1.4. C algorithm for horizontal-vertical erosion.
Applying odd-numbered offsets at each pass might seem less intuitive than
the Manhattan technique, but the mathematical explanation is simple. Recall
that the image contains squared distance, d2 . At every iteration, the algorithm
fills in new distance values by adding an offset value β to the previous distance.
Expressing this in the form of an equation, we have
d2 = (d − 1)2 + β.
Solving for β is simple algebra:
β = 2 ∗ d − 1;
therefore, β iterates through the odd integers.
1.4 Saito-Toriwaki Scanning with OpenCL
Saito and Toriwaki developed another technique that consists of a horizontal stage
of processing followed by a vertical stage [Saito and Toriwaki 94]. Interestingly,
the horizontal stage of processing is not erosion-based and is actually O(n). Their
method is perhaps one of the best ways to generate squared Euclidean distance
on the CPU, because it’s fast and simple to implement. Their algorithm is also
fairly amenable to the GPU, but only when using a compute API such as OpenCL
rather than a purely graphics-oriented API.
1.4. Saito-Toriwaki Scanning with OpenCL 9
Several researchers have improved the worst-case efficiency of the Saito-Toriwaki
algorithm, but their methods often require additional data structures, such as a
stack, and their complexity makes them less amenable to the GPU. (For an ex-
cellent survey of techniques, see [Fabbri et al. 08].) We found the original Saito-
Toriwaki algorithm to be easy to implement and parallelize. At a high level, their
method can be summarized in two steps:
1. Find the one-dimensional distance field of each row. This can be performed
efficiently in two passes as follows:
• First, crawl rightward and increment a counter along the way, resetting
the counter every time you cross a contour line. Write the counter’s
value into the destination image along the way. After the entire row
is processed, the seed image can be discarded.
• Next, crawl leftward, similarly incrementing a counter along the way
and writing the values into the destination image. When encountering
an existing value in the destination image that’s less than the current
counter, reset the counter to that value.
In code, the operations performed on a single row can be expressed as
follows:
// Rightward Pass
d = 0;
for ( x = 0; x < Width ; x ++) {
d = seed [ x ] ? 0 : d +1;
destination [ x ] = d ;
}
// Leftward Pass
d = 0;
for ( x = Width -1; x >= 0; x - -) {
d = min ( d +1 , destination [ x ]);
destination [ x ] = d ;
}
2. In each vertical column, find the minimum squared distance of each pixel,
using only the values computed in Step 1 as input. A brute-force way of
doing this would be as follows:
for ( y1 = 0; y1 < height ; y1 ++) {
minDist = INFINITY ;
for ( y2 = 0; y2 < height ; y2 ++) {
d = destination [ y2 ];
d = ( y1 - y2 ) * ( y1 - y2 ) + d * d ;
minDist = min ( minDist , d );
}
10 1. 2D Distance Field Generation with the GPU
destination [ y1 ] = minDist ;
}
Note the expensive multiplications in the vertical pass. They can be optimized
in several ways:
• The d ∗ d operation can be pulled out and performed as a separate pass on
the entire image, potentially making better use of GPU parallelization.
• The d ∗ d operation can be eliminated completely by leveraging the β trick
that we described in our erosion-based method. In this way, the horizontal
pass would track squared distance from the very beginning.
• The (y1 − y2)2 operation can be replaced with a lookup table because
|y1 − y2| is a member of a relatively small set of integers.
In practice, we found that these multiplications were not very damaging since
GPUs tend to be extremely fast at multiplication.
For us, the most fruitful optimization to the vertical pass was splitting it
into downward and upward passes. Saito and Toriwaki describe this in detail,
showing how it limits the range of the inner loop to a small region of interest.
This optimization doesn’t help much in worst-case scenarios, but it provides a
Figure 1.5. Seed image, rightward, leftward, downward, upward (top to bottom).
1.4. Saito-Toriwaki Scanning with OpenCL 11
substantial boost for most images. To see how to split up the vertical pass, see
the accompanying sample code. The step-by-step process of the Saito-Toriwaki
transformation is depicted in Figure 1.5.
In reviewing the OpenCL implementation of the Saito-Toriwaki algorithm,
we first present a naive but straightforward approach. We then optimize our
implementation by reducing the number of global memory accesses and changing
the topology of the OpenCL kernels.
1.4.1 OpenCL Setup Code
Before going over the kernel source, let’s first show how the CPU-side code sets
up the OpenCL work items and launches them. For the sake of brevity, we’ve
omitted much of the error-checking that would be expected in production code
(see Listing 1.5).
void RunKernels ( cl_uchar * inputImage , cl_ushort * outputImage ,
cl_platform_id platformId , const char * source )
{
size_t horizWorkSize [] = { IMAGE_HEIGHT };
size_t vertWorkSize [] = { IMAGE_WIDTH };
cl_context context ;
cl_mem inBuffer , outBuffer , scratchBuffer ;
cl_program program ;
cl_kernel horizKernel , vertKernel ;
cl_command_queue commandQueue ;
cl_device_id deviceId ;
// Create the OpenCL context
clGetDeviceIDs ( platformId , CL_DEVICE_TYPE_GPU , 1 ,
& deviceId , 0);
context = clCreateContext (0 , 1 , & deviceId , 0 , 0 , 0);
// Create memory objects
inBuffer = clCreateBuffer ( context ,
CL_MEM_READ_O N L Y | CL_MEM_COPY_HOST_PTR ,
IMAGE_WIDTH * IMAGE_HEIGHT , inputImage , 0);
outBuffer = clCreateBuffer ( context , CL_MEM_READ_WRITE ,
IMAGE_WIDTH * IMAGE_HEIGHT * 2 , 0 , 0);
// Load and compile the kernel source
program = c l C r e a t e P r o g r a m W i t h S o u r c e ( context , 1 ,
& source , 0 , 0);
clBuildProgram ( program , 0 , 0 , " -cl - fast - relaxed - math " , 0 , 0);
// Set up the kernel object for the horizontal pass
horizKernel = clCreateKernel ( program , " horizontal " , 0);
clSetKernelArg ( horizKernel , 0 , sizeof ( cl_mem ) , & inBuffer );
clSetKernelArg ( horizKernel , 1 , sizeof ( cl_mem ) , & outBuffer );
12 1. 2D Distance Field Generation with the GPU
// Set up the kernel object for the vertical pass
vertKernel = clCre ateKerne l ( program , " vertical " , 0);
clSetKernelArg ( vertKernel , 0 , sizeof ( cl_mem ) , & outBuffer );
// Execute the kernels and read back the results
commandQueue = c l C r e a t e C o m m a n d Q u e u e ( context , deviceId , 0 , 0);
c l E n q u e u e N D R a n g e K e r n e l ( commandQueue , horizKernel , 1 , 0 ,
horizWorkSize , 0 , 0 , 0 , 0);
c l E n q u e u e N D R a n g e K e r n e l ( commandQueue , vertKernel , 1 , 0 ,
vertWorkSize , 0 , 0 , 0 , 0);
c l E n q ue u e R e a d B u f f e r ( commandQueue , outBuffer , CL_TRUE , 0 ,
IMAGE_WIDTH * IMAGE_HEIGHT * 2 ,
outputImage , 0 , 0 , 0);
}
Listing 1.5. OpenCL Saito -Toriwaki algorithm.
Listing 1.5 uses OpenCL memory buffers rather than OpenCL image objects.
This makes the kernel code a bit easier to follow for someone coming from a CPU
background. Since we’re not leveraging the texture filtering capabilities of GPUs
anyway, this is probably fine in practice.
Also note that we’re using a seed image that consists of 8-bit unsigned integers,
but our target image is 16 bits. Since we’re generating squared distance, using
only 8 bits would result in very poor precision. If desired, a final pass could be
tacked on that takes the square root of each pixel and generates an 8-bit image
from that.
1.4.2 Distance Clamping
The finite bit depth of the target surface leads to an important detail in our
implementation of the Saito-Toriwaki algorithm: distance clamping. Rather than
blindly incrementing the internal distance counter as it marches horizontally, our
implementation keeps the distance clamped to a maximum value like this:
ushort nextDistance = min (254 u , distance ) + 1 u
Even though the target is 16 bit, we clamp it to 255 during the horizontal
scan because it gets squared in a later step. Note that distance clamping results
in an interesting property:
If distances are clamped to a maximum value of x, then any two seed pixels
further apart than x have no effect on each other in the final distance field.
We’ll leverage this property later. For some applications, it’s perfectly fine
to clamp distances to a very small value. This can dramatically speed up the
generation algorithm, as we’ll see later.
Other documents randomly have
different content
The Project Gutenberg eBook of Dumps -
A Plain Girl
This ebook is for the use of anyone anywhere in the United States
and most other parts of the world at no cost and with almost no
restrictions whatsoever. You may copy it, give it away or re-use it
under the terms of the Project Gutenberg License included with this
ebook or online at www.gutenberg.org. If you are not located in the
United States, you will have to check the laws of the country where
you are located before using this eBook.
Title: Dumps - A Plain Girl
Author: L. T. Meade
Illustrator: R. Lillie
Release date: July 7, 2013 [eBook #43120]
Most recently updated: October 23, 2024
Language: English
Credits: Produced by Nick Hodson of London, England
*** START OF THE PROJECT GUTENBERG EBOOK DUMPS - A PLAIN
GIRL ***
L.T. Meade
"Dumps - A Plain Girl"
Part 1, Chapter I.
A Lesson in Patience.
The boys were most troublesome. They never would mind in
the very least when father had one of his worst headaches.
It was not that they did not try to be good—I will say that
Alex had the kindest heart, and that Charley was good-
natured too—but it seemed to me as though they could not
walk quietly; they would stump upstairs, and they would go
heavily across the big attic where they slept, and father was
so fearfully sensitive; the least sound made him start up,
and then he would get into a sort of frenzy and hardly know
what he was doing. He would call out to the boys and
thunder to them to be quiet; and then his head was worse
than ever. Oh, it was all dreadful—dreadful! I sometimes did
not know what to do.
I am going to tell the story of my life as far as I can; but
before I begin I must say that I do wonder why girls, as a
rule, have a harder time of it than boys, and why they learn
quite early in life to be patient and to give up their own will.
Now, of course, if father comes in after his very hard day’s
work, schoolmastering, as he calls it, and when he has one
of his fearful headaches, I sit like a lamb and hardly speak;
but it never enters into Alex’s head, or into Charley’s, that
they ought to be equally considerate. I do not for a minute
want to praise myself, but I know that girls have an
opportunity very early in life of learning patience.
Well now, to begin my story.
I was exactly fifteen years and a half. I should not have a
birthday, therefore, for six months. I was sorry for that, for
birthdays are very nice; on one day at least in the year you
are queen, and you are thought more of than any one else
in the house. You are put first instead of last, and you get
delicious presents. Some girls get presents every day—at
least every week—but my sort of girl only gets a present
worth considering on her birthday. Of all my presents I
loved flowers best; for we lived in London, where flowers
are scarce, and we hardly ever went into the country.
My name is Rachel Grant, and I expect I was a very
ordinary sort of girl. Alex said so. Alex said that if I had
beautiful, dancing dark eyes, and very red lips, and a good
figure, I might queen it over all the boys, even on the days
when it wasn’t my birthday; but he said the true name for
me ought not to be Rachel, but Dumps, and how could any
girl expect to rule over either boys or girls with such a name
as Dumps? I suppose I was a little stodgy in my build, but
father said I might grow out of that, for my mother was tall.
Ah dear! there was the sting of things; for if I had had a
mother on earth I might have been a very different girl, and
the boys might have been told to keep their place and not
to bully poor Dumps, as they called me, so dreadfully. But I
must go on with my story.
I was Rachel or Dumps, and there were two boys, Alex and
Charley. Alex was a year younger than I, and ought really to
have been very much under my control; and Charley was
two years younger. Then there was father, who was quite
elderly, although his children were comparatively young. He
was tall and had a slight stoop, and his hair was turning
grey. He had a very beautiful, lofty sort of expression, and
he did wonders in the great school or college where he
spent most of his time. Our house belonged to the college;
the rooms were large, and the windows looked out on the
grounds of the college and I could see the boys playing,
Alex and Charley amongst them, only I never dared to look
if I thought Alex or Charley could see me; for if they had
caught sight of me it would have been all over with me, for
they did not particularly want the other boys to know they
had a sister.
“If she was a beauty we’d be awfully proud,” said Alex, “but
being only Dumps, you know,”—and then he would wink at
me, and when he did this I felt very much inclined to cry.
Well, these things went on, and I went to school myself and
learnt as hard as I could, and tried to keep the house in
order for father, whom I loved very dearly, and who
sometimes—not very often, but perhaps once or twice, on a
birthday or some special occasion of that sort—told me that
I was the comfort of his life, and I knew that I was patient,
whatever other virtue I might lack.
There came a special evening in the beginning of November.
It had been a drizzling sort of day, and rather foggy, and of
course the old house looked its worst, and it was six months
—six whole months—before I could have a birthday, and the
boys were so loud, and father’s head was so bad, and
altogether it was a most discouraging sort of day. I had
invited Rita and Agnes Swan to come and have tea with me.
They were my greatest friends. I hardly ever dared to ask
them to come, because something would be sure to happen
on the nights when they arrived. But at school that morning
it had seemed to me that I might certainly enjoy a quiet
hour with them, so I said, “If you will come in exactly at
four o’clock—father won’t be in, I am sure, for two hours,
for it is his late day at the school, and it is half-holiday for
the Upper Remove and Alex will be out of the way, and if
Charley does come in we can manage him—we’ll have the
entire house to ourselves from four to five, and can have a
glorious game of hide-and-seek.”
Rita said she would be charmed to come, and Agnes said
the same, and I hurried home to do the best I could for my
friends.
Rita and Agnes were not exactly beautiful; but they were
not like me—no one could have called either of them
Dumps. They had soft, pretty hair which waved about their
little heads, and their features were quite marked and
distinct, and I think their eyes were beautiful, although I am
not absolutely sure. They were rather clever, and often got
praised at school. I am afraid they were inclined to
patronise me, but I thought if I could have them to tea, and
could show them over our large house, and let them see
what a splendid place it was for hide-and-seek, it being a
very old house with lots of queer passages and corners,
they might respect me more and get the other girls in the
school to do so also.
Accordingly, when I got home about one o’clock on that
November day I was in high spirits. But there was my usual
lesson in patience waiting for me; for father came in at
three o’clock instead of at six, as he had done every single
Thursday since I could remember.
“Where are you, Rachel?” he called out when he entered the
house.
I ran to him.
“Oh father, is anything wrong?”
“Only this abominable headache,” he replied. “It is worse
than usual. I am going to my room to lie down. See that the
house is kept quiet, Rachel.”
“Oh yes,” I replied. “Shall I get you a cup of tea?”
“No; I couldn’t touch anything. Just keep the house as quiet
as possible. If those young rascals come in, tell them about
me. I trust you, Rachel, not to allow a sound.”
“Very well, father,” I said.
He never noticed that I was in my best frock, pale-blue with
a sash of the same, and that I had combed and brushed my
hair until it fairly shone. I knew that my hair was thick and
longer than most girls’ hair, and I was proud to let it fall
over my shoulders, and I wondered if Rita and Agnes would
remark it.
But here at once was a stop to our jolly game of hide-and-
seek; we could not play a game of that sort without making
a noise. We must sit in the parlour. The parlour was farthest
away from father’s bedroom. We must sit there and be as
still as possible. We might play games, of course; but then
one could play games at the Swans’ house, which was a
very ordinary, everyday sort of place, not a bit like ours,
which at least was quaint and out of the common.
I had ordered queen-cakes for tea, and a fresh pot of jam
to be opened, and I was all expectation, and primed, as
Alex would say, to exert myself to the very utmost to
entertain my friends, when who should come thundering up
the steps, making a most horrible noise, but the boys, with
two other boys bearing them company. I rushed out to the
hall.
“You mustn’t really, Alex,” I said.
“Mustn’t what?” he cried, looking at my excited face.
“What’s up now, Dumps?”
The other boys were strangers. One had red hair, and the
other was dark. He looked like a foreigner; his hair fell
straight in two lines down his forehead and almost met his
eyebrows. He was sparely built, and very tall, and had great
big hands. Alex glanced back at him.
“I wanted to take these fellows over the house,” he said.
“This is Von Marlo”—here he introduced the taller boy—“and
this is Squibs. You must have heard me talk of Squibs. Now,
don’t stand in the way; let us come in. Von Marlo is Dutch,
and very proud of his country—aren’t you, Von Marlo?”
Von Marlo smiled, and bowed to me.
“Now get out of the way, Dumps,” said Alex. “And what
have you put on your best frock for, and why are you all
prunes and prisms? What is the matter?”
“Only that father is at home. He is lying down; he has a
shocking headache. You really mustn’t make a noise.—You
must go away, please, Mr Von Marlo and Mr Squibs.”
“Oh, how jokingly funny!” exclaimed Alex, and he burst into
a loud laugh and sank down on the bench in the hall. But
the Dutch boy, Von Marlo, came up to me and made
another little bow, and took my hand as though he would
kiss it; he raised it to within a few inches of his lips and
then dropped it again. I was told afterwards that this was
the Dutch way of showing reverence to a lady, and I was
immensely touched by it. He said, “Certainly, Miss Grant,
we will go away. I did not know when Grant asked me to
come in that your father was ill.”
“But I say, the Professor was in his class holding forth not
half-an-hour back,” said Squibs, whose real name was
Squire.
“Well, he’s lying down now, and there can be no noise,” I
said.
I had scarcely uttered the words before up the steps came
my own two special visitors, Rita and Agnes Swan.
“Oh Jiminy!” cried Alex; and he stepped back as the two
young ladies sailed in.
“How do you do, Rachel?” said Rita.
“How do you do, Rachel?” said Agnes.
They were also dressed in their best, and were evidently
highly pleased and intended to have a good time. They did
not at all object to the fact that four rather tall, ungainly
schoolboys were standing about in the hall.
“You know my brothers, don’t you, Rita?” I said, presenting
Alex and Charley. “And this is Mr Von Marlo, and this is Mr
Squire.”
Alex and Charley reddened up to the roots of their hair;
Squibs looked as though he could not possibly get any
redder—he was nearly always scarlet; but the Dutch boy,
Von Marlo, bowed in the most graceful style, and then stood
quite at his ease, glancing at the girls.
“I say,” said Alex, coming up to me and speaking in a very
loud semi-whisper, “have they come to tea?”
“Yes—yes. Do go away—please go away—and take the boys
with you.”
“But are there cookies and good things for tea?”
“Yes; but there really isn’t enough for four extra people. Do
go away, Alex. I’ll have something nice for your supper by-
and-by. Do! there’s a good boy.”
But neither Alex nor Charley would see the fun of that, and
I am sure those girls who take the trouble to read my
history will guess at my mortification when I tell them that
four extra guests sat down to a tea-table only prepared for
three.
Now Hannah, our servant, was by no means noted for her
good temper. She brought in fresh bread-and-butter, fresh
tea, fresh jam; but the fearful difficulty of keeping the room
quiet and of making those boys abstain from laughter, of
making even Rita and Agnes behave themselves, was
enough to wear any poor girl out. I do not know what I
should have done but for the Dutch boy, Von Marlo. He saw
that I was annoyed, and he came up to me and offered me
all the help he possibly could.
“It is quite a shame,” he said; “and you looked so nice when
you opened the door. I thought you were the very prettiest
girl I had ever laid eyes on. You see, I have not been in
England more than two months. I have come here to go to
this famous school.”
“You speak English very well,” I said.
“Oh yes, I learnt that in Holland; we all learn it there. We
learn English, German, and French as soon as ever we can
speak at all, I think; for, you see, our language—Dutch—is
not much use to us outside our own country. There is
nothing in that,” he continued modestly. “Now, what can I
do to help you?”
I looked at him, and my ruffled spirits became soothed.
After all, why should I not make the best of things?
“I’ll try to keep the fellows quiet,” said Von Marlo; “and you
needn’t call me Mr—I am only a schoolboy. You can just say
Von Marlo, as I am sure you say Squibs to Squire. We can
all be jolly together. What do you say?”
“Done!” I cried; and after that the meal went swimmingly.
It was amazing what those fellows managed to eat; and it
was still more amazing to see how Rita and Agnes enjoyed
themselves. It was the thought of their disappointment
which had so terribly annoyed me when the four boys
insisted on bursting into our parlour and forcing themselves
into our presence; but I soon saw that Rita and Agnes were
only delighted. They laughed and joked, and as they
laughed Alex and Charley became like lambs of sweetness
and gentleness. Dear, dear! how nice a brother can be to
other people’s sisters! It is quite extraordinary. I bent over
to Rita and whispered to her, “I hope you are not vexed.”
“Vexed?” she whispered back. “No; I’m sure I’m delighted. I
did not think it was to be a big party of this sort; and really
the boys of the upper school are almost like men. It is very
nice indeed; I am enjoying myself extremely.”
And so she was, and so was Agnes. When tea was over,
however, an anxious moment arrived. We could not play any
noisy games, and the boys immediately declared that they
were not going away.
“We are going to see the fun out now,” said Alex. “Never
mind to-morrow’s work. I’ll do that in the small hours—burn
the candle, you know.”
Here he winked at Agnes, and she winked back at him,
thinking herself exceedingly witty.
Games were proposed, and games were begun; but, alas!
how could seven young people keep absolutely quiet? I was
trembling all over. If father were but to come down and see
the absolute riot in the parlour, I didn’t know what would
happen. I was certain of one thing: neither Rita nor Agnes
would ever be allowed to have tea with me again.
After a time I did a very injudicious thing. I left the room. I
ran upstairs. I listened outside father’s room and heard him
moving about. I knocked, and immediately the door was
flung open, and there was father in his dressing-gown, with
his beautiful grey hair pushed back off his forehead.
“What’s all that murmuring and muttering and shuffling that
is going on downstairs?” he said. “And how flushed your
cheeks are! And there is a smear of jam on one of them.
What have you been doing?”
“Having tea, father.”
“You never offered me a cup.”
“Oh father! when you first came in I offered to get you
some.”
“Well, I’d like some now. Bring me up something to eat.”
“Then, father darling, is your head better?”
“Yes, my dear, yes. Go downstairs and bring me up a tray
full of food—toast and an egg and some tea. Bring them up
with your own hands. See there isn’t a sound. If I have two
or three hours of quiet I shall be quite fit to resume my
work to-night. I have to lecture in Hall at nine o’clock this
evening. I shall not be able to utter a word if this headache
continues. Now, Rachel, be off; set to work and get me
some food at once, as fast as ever you can.”
I was half-way downstairs when my father’s voice called
after me:
“Do stop all that whispering and whistling and noise. I can’t
imagine what is happening.”
“I will do what I can, father,” I said.
Part 1, Chapter II.
The Poached Egg.
I returned to the boys and to my school friends.
“Father is awake,” I said, “and he complains of the noise we
are making.”
“Noise?” cried Alex. “Why, we are as mum as mice!”
“People must breathe, you know,” said Agnes in what I
considered a very impertinent way.
I stared at her. She had no right to speak like that of my
father, the great Professor Grant; for my father was a
member of the Royal Society, no less, and you can imagine
that to hear such talk from a silly little girl like Agnes Swan
was, to say the least of it, disagreeable. So I drew myself
up; but then I caught Von Marlo’s eyes, and I felt soothed,
for he seemed to understand.
“If the Professor wishes it,” he said, “we will, of course,
hardly speak at all.—It might be best,” he added, turning to
Alex, “if we all went away. What do you think?”
“Please yourself, Von,” said Alex, speaking in a very
patronising way, and flinging himself back in a deep chair.
“Squibs and Charley and I stay; and as you are the quietest
of the party, and inclined to patronise Dumps, I don’t see
why you should go.”
Von Marlo came straight up to me and said:
“Can I do anything for you? They say I patronise you, but
that is not true. I don’t exactly know what they mean by
patronise, but I will do all I can to help you, for you are
quite the nicest little girl I have met since I came to
England.”
Agnes and Rita seemed neither of them to thoroughly
appreciate these remarks of Von Marlo’s, for he was really
the biggest and most imposing-looking of the four boys.
Even Alex, who was a handsome fellow, looked very young
beside him. As to me, I felt soothed. Of course, you must
understand that if you have been called Dumps all your life,
and told to your face that you haven’t one vestige of good
looks, it must be a sort of pleasure to have a person
suddenly inform you that you are—oh! better than good-
looking—the very prettiest girl he has seen in the whole of
the country. I felt, therefore, a flush of triumph stealing to
my cheeks, and then I said, “Please keep things as quiet as
you can. I must go to the kitchen to get some tea for father.
Please don’t let them be noisy.”
“I’ll sit on them if they are,” said Von Marlo.
But Alex called out, “Go along, Von, and help her; that’ll be
the best way. Good gracious! she’s in such a state of mind,
because you are noticing her and bolstering her up, that she
will fall, as likely as not, going down those slippery
backstairs. Go along with her, old chap, and help her.”
“Yes, come,” I said, for I could not resist it.
So Von Marlo and I found ourselves in the big hall; then he
took my hand and we went along the passage, and then
down another passage, and then we opened a door and I
called to Hannah.
“Hannah, are you downstairs?”
We were looking into pitch-black darkness, but we heard a
muffled voice say, “Yes, Miss Rachel? Sakes alive! What’s
wanted now?”
Then Hannah appeared at the foot of the stairs, holding a
lighted candle.
“I’m coming down,” I said, “and I’m bringing a gentleman
with me.”
Hannah very nearly fell in her amazement, but I went
steadily down, Von Marlo following me.
“It is a very old house,” I whispered, “and some people say
it is haunted. But you are not afraid of ghosts, are you?”
“I think they are the jolliest things in the world!” was his
reply.
He said the word jolly in a very funny way, as though he
was not accustomed to the word, and it sounded quite
sweet.
At last we got to the lower regions, and then, guided by
Hannah’s candle—which was really only like a very little
spark of light—we found our way into the kitchen.
“Once this was a grand house and grand people lived here,”
I said. “Father lives here now because it belongs to the
college. The house is a great deal too big for us, but it is a
glorious place for hide-and-seek. This is the kitchen—
monstrous dinners used to be cooked here.”
“Now then, Miss Rachel, what do you want?” said Hannah.
“And I think young gents as ought to be at school ought to
keep out of the Professor’s kitchen. That’s what I think.”
“Oh, please, Hannah,” I said, “this gentleman is from over
the seas—he comes from Holland, where the beautiful tulips
are grown, and his name is Mr Von Marlo.”
“Catch me trying to say a mouthful of a name like that!”
was Hannah’s rejoinder.
“He is exceedingly kind,” I continued, “and he is going to
help us.”
“Yes, I will help you if you will let me,” said Von Marlo,
speaking in his slow and rather distinct way, and not
gabbling his words as we English do.
“I want tea and toast and an egg for father; he is waiting
for them, and we must hurry,” I said. “Hannah, be as quick
as you can.”
“My word,” said Hannah, “what a fuss!”
She was really a kind creature. She must have been good to
live with us in that queer old house, for she was actually the
only servant we kept. She must have been brave, too, to
spend so much of her time in that desolate kitchen and in
those black passages, for gas had never been laid on in the
bottom portion of the old house, and it smelt very damp,
and I am sure the rats had a good time there at night. But
Hannah, forty-five years of age, with a freckled face and
reddish hair, and high cheek-bones and square shoulders,
had never known the meaning of the word fear.
“Ghosts?” she would cry. “Don’t talk nonsense to me! Rats?
Well, I guess they’re more afraid of me than I am of them.
Loneliness? I’m a sight too busy to be lonely. I does my
work, and I eats my vittals, and when bedtime comes I
sleeps like a top. I’m fond of the Professor, and proud of
him, he’s so cliver; and I’m fond of Miss Rachel, whom I’ve
known since she was born, and of the boys, although they
be handfuls.”
This was Hannah’s creed; she had no fear, and she was fond
of us. But she had a rough tongue, and could be very rude
at times, and could make things unpleasant for us children
unless we humoured her.
It was Von Marlo, the Dutch boy, who humoured her now.
He offered to cut the bread for toast, and he not only
offered, but he went boldly to the cupboard, found a loaf,
and cut most delicate slices, and set to work toasting them
before a clear little fire in a small new range at one end of
the kitchen before Hannah had time to expostulate. Then he
suggested that father’s egg should be poached, not boiled,
and he found a saucepan and put it on the fire and
prepared to poach the egg. And when Hannah said, “My,
what a fuss!” he found the egg, broke it into the boiling
water, poached it beautifully, and put it on the toast. Really,
he was a wonderful boy; even Hannah declared that never
had she seen his like.
The tea was made fragrant and strong, and we put it on a
little tray with a white cloth, and Von Marlo carried it for me
up the dark stairs. We reached the hall, and then we stood
and faced each other.
“You are going up all those other stairs with that tray?” said
Von Marlo. “Then I insist upon carrying it for you.”
“But suppose father should come out? He sometimes does,
you know,” I whispered.
“And if he does, what matter?” said Von Marlo. “He won’t
eat us! Come along, Miss Rachel.”
I was very glad he did not call me Dumps. He must have
heard Hannah call me Miss Rachel, for, as far as the boys
were concerned, I might have been christened Dumps, for
they never addressed me as anything else.
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
textbookfull.com